Отладка проблем, связанных с переполнением стека

Данная статья описывает способы отладки проблем, связанных с переполнением стека, возникающий при использовании Informix C UDR.

Введение

"Руководство программиста по Informix® DataBlade™ API" доступно для загрузки в Информационном Центре Informix. Раздел "Managing Stack Space" описывает создание пользовательских функций (UDR). Данная статья предоставляет дополнительную информацию и советы по отладке.

Нижеприведенная информация справедлива вне зависимости от того, выполняется ли UDR на определенном пользователем виртуальном процессоре (VP), или же на CPU VP. Стек нити может быть перемещен на определенный пользователем виртуальный процессор непосредственно перед выполнением UDR.


Стек какого размера выделяется для UDR?

Размер стека, доступного для UDR, зависит от того, как UDR была создана:

  • с помощью модификатора STACK, который позволяет UDR использовать свой специально выделенный стек,

  • без модификатора STACK, что означает, что UDR будет использовать стек, выделяемый сервером, совместно с нитью, выполняющей запрос. Размер стека в данном случае будет определяться значением параметра STACKSIZE в файле конфигурации onconfig.

Модификатор STACK

Выражения СREATE PROCEDURE или CREATE FUNCTION имеют опциональный модификатор STACK, который позволяет Вам указать размер пространства стека в байтах, который необходим для выполнения UDR.

Если Вы используете модификатор STACK при создании UDR, сервер будет выделять и освобождать пространство стека при каждом выполнении UDR. Действительный доступный размер равен значению STACK в байтах минус некоторые накладные расходы, зависящие от количества аргументов функции.

Если величина STACK меньше, чем значение параметра STACKSIZE в файле onconfig (см. следующий раздел), то размер выделяемого для UDR стека будет автоматически округляться до величины STACKSIZE.

Параметр конфигурации STACKSIZE

Файл конфигурации onconfig включает в себя параметр STACKSIZE, который определяет размер стека по-умолчанию для пользовательских нитей.

Если Вы не указываете STACK при создании UDR, сервер не выделяет дополнительное пространство стека для выполнения этой UDR. Вместо этого UDR использует пространство стека, выделенное для выполнения запроса. Доступный размер стека будет зависеть от накладных расходов на выполнение функции на уровне SQL.

Стек для нити выделяется единожды для конкретной нити, выполняющей запрос. Быстродействие выше, когда UDR делит один стек с нитью, так как сервер не тратит ресурсов на выделение дополнительного стека для каждого вызова UDR. С другой стороны, если размер используемого UDR стека приближается к значению STACKSIZE, это может вызвать переполнение стека при вызове функции в составе сложного запроса (в этом случае для выполнения UDR будет доступно меньше пространства стека).

Следует помнить, что не стоит устанавливать завышенное значение STACKSIZE, так как это затронет все пользовательские нити.


Когда необходимо управлять размером стека?

YВы должны управлять пространством стека если UDR выполняет рекурсивные вызовы или если UDR требует большего пространства стека, чем доступно по-умолчанию в стеке нити запроса (STACKSIZE).

Есть два способа увеличения стека для выполнения UDR:

  • Указать модификатор STACK при создании UDR.

  • Использовать mi_call() для выполнения рекурсивных вызовов (см. пример в "Руководстве программиста по Informix DataBlade API").

Если Вы не указываете размер через STACK, и если Вы не используете mi_call() для увеличения текущего стека, и если при этом UDR делает что-то, что требует большого пространства стека, то это вызовет переполнение стека.

Следует принять во внимание, что некоторые функции вида mi_* добавляют новый сегмент стека для их собственного выполнения. Эти сегменты освобождаются при возвращении к вызвавшей функцию UDR.


Что делать, если что-то идет не так?

Наблюдение за использованием стека

Цель наблюдения - идентификация конкретной UDR, которая вызывает переполнение стека, чтобы Вы могли изменить значение STACK специально для конкретной UDR.

  • Наблюдение использования стека с помощью команды "onstat -g sts"

  • Наблюдение за сессией, выполняющей запрос SQL, с помощью "onstat -g ses session_id"

После идентификации запроса SQL, который заканчивается переполнением стека, следует определить использование стека путем раздельного выполнения запросов с UDR, которые входят в состав оригинального запроса.

Вы можете динамически устанавливать значение STACK для UDR. Например:

alter function MyFoo (lvarchar,lvarchar) 
with (add stack=131072);

После изменения значение STACK следует протестировать оригинальный запрос, чтобы убедиться в том, что он теперь работает стабильно.

Увеличение STACKSIZE

В качестве альтернативы попробуйте увеличить значение STACKSIZE. Проверьте, решило ли это проблему. (Позже не забудьте вернуть старое значение).

Если увеличение STACKSIZE не помогло, скорее всего проблема в повреждении памяти. Вот несколько предложений:

  • Включите memory scribble и проверку пулов памяти. Раздел "Debugging Problems" в статье Memory Allocation for UDRs объясняет, как это сделать.

  • Пересмотрите использование mi_lvarchar. Особое внимание следует уделить местам, где mi_lvarchar передается функции, которая ожидает получить нуль-терминированная строку в качестве аргумента.

  • Сократите количество CPU (или пользовательских) VP до одного, чтобы воспроизвести проблему быстрее.


mi_print_stack() -- Solaris

Informix Dynamic Server для OC Solaris включает функцию mi_print_stack(), которая может быть вызвана в UDR. По-умолчанию эта функция сохраняет фрейм стека в следующий файл:

/tmp/default.stack

Вы не можете изменить имя файла вывода, но можно изменить его расположение изменив значение переменной окружения DBTEMP. Убедитесь, что в директорию $DBTEMP разрешена запись пользователю informix. Любые ошибки, возникающие при выполнении mi_print_stack() выводятся в $MSGPATH.

Данная функция доступна только для OC Solaris.


Глоссарий

Термины и сокращения, используемые в данной статье:

UDRUser-Defined Routine
VPVirtual Processor

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management
ArticleID=782783
ArticleTitle=Отладка проблем, связанных с переполнением стека
publish-date=12262011