Форум » Clipper » Ошибка DBSETLOC(0) » Ответить

Ошибка DBSETLOC(0)

pirat: Провожу пересчет по всем полям в базе. При достижении определенного номера выскакивает ошибка: DBSETLOC(0) Невосстановимая ошибка 667: Переполнение стека вычисления. Кто-нибудь сталкивался с такой проблемой? Подскажите, что можно сделать?

Ответов - 5

Dima: Может это поможет http://clipper.borda.ru/?1-0-0-00000350-000-0-0

pirat: Спасибо за совет! Но, к сожалению, ни разу не пользовался Blinker.

Сыроежка: pirat пишет: Провожу пересчет по всем полям в базе. При достижении определенного номера выскакивает ошибка: DBSETLOC(0) Невосстановимая ошибка 667: Переполнение стека вычисления. Кто-нибудь сталкивался с такой проблемой? Подскажите, что можно сделать? Переполнение стека - это переполнение стека Clipper. То есть это означает, что у вас возможно в какой-нибудь функции или выражении указано слишком много публичных или приватных переменных, параметорв функций, полей базы данных. Кроме того у вас могут быть много массивов или символьных строк. Так как в стек Clipper для каждого типа данных заносит структуру размером 14 байт, то не удивительно, что стек при определенных обстоятельствах может переполниться. Попробуйте уменьшить глубину цепочек вызовов функций, а также количество переменных и массивов. Если у вас много публичных или приватных переменных, то лучше их заменить локальными переменными, так как все публичные и приватные переменные занимают место в специальной таблице Clipper с определениями этих переменных.


Сыроежка: Чтобы вы располагали более полной информацией, позволяющей вам локализовать причину ошибки. Я приведу общий анализ. Функция __DBSETLOC располагается в объектном модуле DBCMD5. Если посмотреть ее исходный код, то единственное, что она делает, это устанавливает кодовый блок bFor для активной базы данных, если этот кодовый блок был передан в качестве параметра, и возвращает текущее значение блока bFor. bFor - это кодовый блок, который формируется, когда вы, например, вызываете команду LOCATE, указав в ней опцию FOR. Тогда команда LOCATE, которая реализована с помощью Clipper функции __dblocate, то есть prg модуля, вызывает __DBSETLOC и передает ей этот кодовый блок bFor, который соответствует опции команды LOCATE FOR. Что может вызвать аварийное завершение функции __DBSETLOC? Единственное - это вызов из этой функции другой внутренней функции Clipper __GetGrip из объектного модуля STACK. Что делает эта функция? Она пытается зафиксировать указатель на кодовый блок в стеке Clipper. Эти фиксированные указатели обрабатываются следующим образом. Если Clipper первый раз пытается фиксировать указатель, то из стека Clipper выделяется некоторый объем памяти для этих указателей. Когда этот объем исчерпывается, то Clipper снова выделяет дополнительную память из стека Clipper. Когда потребность в фиксированном указателе нет, то Clipper вызывает внутреннюю функцию __DropGrip. Но память при этом не возвращается стеку! Просто освобожденные указатели объединяются в односвязный список и помечаются как удаленные. Когда Clipper нужнофиксировать какой-то указатель, то он первым делом просматривает этот список освобожденных указателей. Не только функция __DBSETLOC выполняет фиксацию указателей на данные в стеке с помощью __GetGrip, но и другие функции, например, при работе со строками, или массивами выполняют подобную операцию. Итак, подытожим. Ошибка возникла в __DBSETLOC при вызове функции __GetGrip, которая в свою очередь не нашла места в стеке, чтобы зафиксировать указатель на кодовый блок bFor. В этом случае вызывается функция __efault, которая пытается каким-то образом получить память, и если ей не удается, то среди прочих сообщений об ошибке, она выдает сообщение с номером 667, которое вы и получили. Какой вывод можно сделать из моего анализа? Причиной ошибки является не сама функция __DBSETLOC, а предыдущий ваш код. аварийное завершение __DBSETLOC - это лишь следствие переполнения стека другими операциями вашей программы. То есть сообщенная вами информация не позволяет сделать заключение, какое место в коде вашей программы стало причиной ошибки. Я лишь могу предположить, что у вас очень много одновременно используется строк, массивов и т.д. Кроме того, если вы используете одновременно все 255 баз данных и для каждой из них выполняете LOCATE, то все 255 баз данных будут хранить кодовый блок bFor. Этот ткодовый блок в любой случае создается командой LOCATE, даже если вы сами не указываете опцию команды FOR. То есть по умолчанию эта команда его кладет равным следующему кодовому блоку [pre2]IF ( ISNIL( bFor ) ) bFor := { || .T. } ENDIF [/pre2] Я конечно понимаю, что вам не стало легче от сообщенной мной информации, но тем не менее вы по крайней мере можете считать, что причина ошибки не в самой __DBSETLOC, а в другом месте вашей программы.

Сыроежка: Я хотел бы еще добавить, что возможно при закрытии базы данных операция закрытия забывает освободить указатель на bFor. Отсюда при частом использовании команды LOCATE может происходить переполнение стека. Это хорошо бы было проверить. Проверку сделать очень просто. Нужно в цикле, допустим, из 100 итераций выполнить следующее: 1) вывести значения внутренних переменных Clipper __estat и __estatlow ; 2) открыть базу данных; 3) вызвать __DBSETLOC, передав ей какой-нибудь кодовый блок 4) закрыть базу данных. Если при выполнении этого цикла значение __estat будет изменяться и приближаться к значению __estatlow, то значит, что при закрытии bFor не освобождается.



полная версия страницы