Отладка приложений, в которых возникают проблемы с распределением памяти с помощью функции malloc(), очень часто требует больших усилий и не всегда дает желаемые результаты. Чаще всего проблемы бывают вызваны записью данных за границами выделенного буфера. Такая операция не влечет за собой немедленных последствий, и ошибка возникает только на этапе, когда потребуются данные, которые хранились в ошибочно занятой области памяти ранее.
Подсистема управления памятью AIX снабжена отладчиком, позволяющим отслеживать ситуации ошибочной совместной записи и чтения одних и тех же областей памяти, а также операции повторного освобождения и выделения одних и тех же областей памяти с помощью функции malloc(). Управление отладчиком осуществляется в момент запуска процесса с помощью переменных MALLOCTYPE и MALLOCDEBUG.
Если отладчик обнаруживает ошибку, он в большинстве случаев выполняет функцию abort() или передает сигнал нарушения сегментации (SIGSEGV). Как правило, при обнаружении ошибки приложение немедленно останавливается, и создается файл core.
Отладчик может применяться только с программами, использующими стандартные средства распределения памяти. Отладчик не поддерживает malloc для AIX версии 3.1.
По умолчанию отладчик malloc выключен. Для того чтобы настроить и включить его, нужно задать следующие переменные среды:
Для запуска отладчика malloc с параметрами по умолчанию нужно задать переменную MALLOCTYPE:
Для включения отладчика с нестандартными параметрами нужно задать обе переменные MALLOCTYPE и MALLOCDEBUG:
где опции - список опций конфигурации через запятую.
Если отлаживаемая программа часто вызывает функцию malloc(), то может быть полезным увеличить объем памяти, доступный программе, с помощью команды ulimit или команды ld с опцией -bmaxdata. Подробная информация об этом приведена в разделе "Дисковая и оперативная память" далее в этой главе.
С помощью переменной MALLOCDEBUG можно задать следующие опции конфигурации отладчика malloc:
Все эти опции подробно описаны ниже.
Переменная MALLOCDEBUG должна быть задана в следующем формате:
MALLOCDEBUG=[[ align:n | postfree_checking | validate_ptrs | override_signal_handling | allow_overreading | report_allocations | record_allocations],...]
Можно указать несколько опций через запятую, как в следующем примере:
MALLOCDEBUG=align:0,validate_ptrs,report_allocations
Каждая опция конфигурации может быть указана в переменной MALLOCDEBUG не более раза. Если какая-либо опция указана несколько раз, то будет применяться последнее из указанных значений.
Переменная MALLOCDEBUG применяется только в случае, если переменной MALLOCTYPE присвоено значение "debug":
Ниже подробно описаны все опции MALLOCDEBUG:
Примечания:
- Более подробные сведения об опции align:n приведены в разделе "Дополнительная информация об опции align:n" да лее в этой главе.
- Выравнивание по границе ячеек в 1 слово соответствует значению align:4.
- Программы, в которых применяются компоненты DCE, должны использовать значение align:8. Применение других значений может привести к непредсказуемым результатам.
Примечание:
- Если вы укажете опцию postfree_checking, то будет автоматически включена опция validate_ptrs.
Если вызывающая программа блокирует или перехватывает сигналы SIGSEGV и SIGIOT, то отладчик не сможет сообщать об ошибках. Для таких ситуаций предусмотрена опция override_signal_handling.
Если указана опция override_signal_handling, то отладчик будет выполнять
следующие действия при вызове любой функции распределения памяти (malloc(),
free(), realloc() или calloc()):
Если обработчик сигналов приложения будет изменять действие для сигнала SIGSEGV между вызовами функций распределения памяти, а затем выполнит недопустимую операцию, то отладчик не сможет выдать сообщение об ошибке и в этом случае (приложение не будет завершено, а файл core не будет создан).
Примечания:
- Опция override_signal_handling неэффективна при работе с приложениями с несколькими нитями, поскольку отладчик пользуется функцией sigprocmask(), при том что многие многонитевые приложения пользуются функцией pthread_sigmask().
- Если нить программы вызывает функцию sigwait(), не включая SIGSEGV и SIGIOT в набор сигналов, и отладчик обнаружит ошибку в такой нити, то нить зависнет, поскольку отладчик может генерировать только сигналы SIGSEGV и SIGIOT.
- Если в функцию ядра будет передан недопустимый указатель, то в функции ядра возникнет ошибка. Как правило, в таких ситуациях функции ядра возвращают код ошибки EFAULT. Если программа не проверяет коды возврата системных вызовов, то такие ошибки могут проходить незамеченными.
Примечания:
- Если вы укажете опцию report_allocations, то будет автоматически включена опция record_allocations.
- Для любой программы будет показана по крайней мере одна активная область, соответствующая обработчику atexit(), создающему данный отчет.
Информация о выделенной области памяти хранится до тех пор, пока эта область не будет освобождена.
Следующая формула позволяет определить, какой критерий будет применяться отладчиком при выделении памяти и определении допустимости запросов на чтение и запись данных. Здесь размер - это размер выделяемой области памяти в байтах, а n - значение опции MALLOCDEBUG=align:n:
((((размер / n) + 1) * n) - размер) % n
Следующие примеры иллюстрируют зависимость между значением опции align:n и тем, насколько далеко за границу выделенной области памяти отладчик разрешит заходить программе:
MALLOCTYPE=debug MALLOCDEBUG=align:2,postfree_checking,override_signal_handling
Отладчик будет действовать следующим образом:
MALLOCTYPE=debug MALLOCDEBUG=align:0,postfree_checking,override_signal_handling
В данном случае программе будет запрещено выходить за границу выделяемой области вне зависимости от ее размера.
При возникновении ошибки отладчик либо вызывает функцию abort(), либо передает сигнал нарушения сегментации (SIGSEGV). Если при включенном отладчике программе удалось нормально завершить работу (не функцией abort() и не в результате нарушения сегментации), это означает, что в подсистеме malloc не было обнаружено ни одной ошибки.
Как правило, при обнаружении ошибки приложение немедленно останавливается, и создается файл core. Если ошибка вызвана попыткой чтения или записи данных за границей выделенной области памяти, то сигнал о нарушении сегментации будет выдан на инструкции, вызвавшей обращение к памяти. Если ошибка будет обнаружена одной из функций работы с памятью (malloc(), free(), realloc() или calloc()), то будет показано сообщение об ошибке и вызвана функция abort().
Поскольку работа отладчика заключается в проведении постоянных проверок в ходе работы программы, применение отладчика существенно снизит производительность подсистемы malloc, но не до такой степени, при которой дальнейшая работа приложений будет невозможна. Поэтому отладчик рекомендуется включать только в случаях, когда вам требуется определить конкретную причину известной ошибки. После устранения ошибки отладчик стоит выключить для обеспечения нормальной производительности подсистемы malloc.
Со включенным отладчиком подсистеме malloc требуется существенно больше памяти для работы. На выполнение каждого запроса malloc() дополнительно расходуется такое количество страниц памяти, в которое можно уместить "4096+2*sizeof(unsigned long)". Это может вызывать серьезные проблемы при работе с большими программами, но отладка большинства приложений не сильно скажется на расходе памяти.
Если отлаживаемая программа часто вызывает функцию malloc(), это может привести к серьезному расходу памяти и сделать невозможным нормальное выполнение программы в пределах одного сегмента. В таких случаях может быть полезным увеличить объем памяти, доступный программе, с помощью команды ulimit или команды ld с опцией -bmaxdata.
При выполнении программ с отладчиком следует задать ограничения ulimit для данных (-d) и стека (-s) следующим образом:
ulimit -d unlimited ulimit -s unlimited
Опции -bmaxdata следует присвоить значение 0x80000000 - в этом случае процессу будет доступен максимальный возможный объем памяти (8 сегментов для 32-разрядного процесса).
После отключения отладчика следует восстановить исходные значения ulimit и -bmaxdata.
Команда ulimit и опция -bmaxdata подробно описаны в разделе Глава 8, Поддержка программ большого объема.
Отладчик может применяться только с программами, использующими стандартные средства распределения памяти. Отладчик не поддерживает malloc для AIX версии 3.1.
Отладчик не рассчитан на постоянное применение. Хотя он спроектирован таким образом, чтобы минимизировать снижение производительности системы, такое снижение все же может быть существенным при широком применении отладчика. В частности, если вы укажете MALLOCTYPE=debug в файле /etc/environment (для применения отладчика для всех процессов системы), то скорее всего стабильная работа системы будет нарушена (например, из-за постоянных обращений к пространству подкачки). Отладчик следует применять только в тех случаях, когда это действительно необходимо.
Следует отметить, что отладчик не рассчитан на применение с определенными программами. Поскольку отладчик отводит отдельную страницу памяти для каждого вызова malloc(), расход памяти у программ, выделяющих большое число небольших участков памяти, может очень сильно возрасти. Недостаток памяти или пространства подкачки при выполнении таких программ может привести к новым сбоям, не имеющим отношения ни к программам как таковым, ни к отладчику.
Примером такой программы может служить сервер X, выполняющий огромное количество запросов на выделение очень маленьких участков памяти во время инициализации и в ходе дальнейшей работы. Попытка запустить сервер X с отладчиком (с помощью команды X или xinit) неминуемо приведет к аварийному завершению сервера X из-за недостатка памяти. Это известное ограничение отладчика. В то же время большинство клиентов X можно без проблем запускать с отладчиком. Для запуска клиента X с отладчиком выполните следующие действия:
Глава 8, Поддержка программ большого объема
Функции malloc, free, realloc, calloc, mallopt, mallinfo, alloca и valloc в книге AIX 5L Version 5.1 Technical Reference: Base Operating System and Extensions Volume 1.