• Переменная среды MALLOC_CHECK_ (обратите внимание на последний символ подчеркивания) служит тем же целям, что и функции mcheck() и mprobe(). (Примечательная разница между этими двумя технологиями состоит в том, что использование MALLOC_CHECK_ не требует внесения изменений в код и перекомпиляции программы.) Устанавливая для этой переменной различные целочисленные значения, мы можем управлять тем, как программа реагирует на ошибки выделения памяти. Возможными значениями для установки являются:
• 0 — означает игнорирование ошибок;
• 1 — устанавливает вывод диагностируемых ошибок на устройство стандартной ошибки — stderr;
• 2 — означает вызов функции abort() для прекращения выполнения программы.
Использование MALLOC_CHECK_ не позволяет обнаружить абсолютно все ошибки выделения и высвобождения памяти. С ее помощью можно найти только самые характерные из них. Тем не менее эта технология является быстродействующей и простой в использовании, а также имеет низкий уровень издержек в ходе выполнения программы по сравнению с применением библиотек отладки malloc. Из соображений безопасности установка значения для MALLOC_CHECK_ программами с полномочиями setuid и setgid игнорируется.
Дополнительные сведения обо всех вышеперечисленных возможностях можно найти в руководстве по glibc.
Библиотека отладки malloc предлагает такой же API, как и стандартный пакет malloc, но выполняет дополнительную работу по отлавливанию ошибок, допущенных при выделении памяти. Чтобы воспользоваться такой библиотекой, приложение следует скомпоновать вместе с ней, а не с пакетом malloc в стандартной библиотеке C. Поскольку использование таких библиотек обычно приводит к замедлению операций в ходе выполнения программы, увеличению потребления памяти или же и тому и другому вместе, их следует использовать только для отладки. После этого, при создании эксплуатационной версии приложения, нужно вернуться к компоновке со стандартным пакетом malloc. К таким библиотекам относятся Electric Fence (http://www.perens.com/FreeSoftware/), dmalloc (http://dmalloc.com/), Valgrind (http://valgrind.org/) и Insure++ (http://www.parasoft.com/).
Библиотеки Valgrind и Insure++ способны обнаруживать многие другие виды ошибок, кроме тех, что связаны с выделением памяти в куче. Подробности можно найти на сайтах с их описаниями.
Управление пакетом malloc и отслеживание его работы
В руководстве по библиотеке glibc дается описание нестандартных функций, которые могут использоваться для отслеживания и управления выделением памяти теми функциями, что входят в пакет malloc. Среди них можно отметить следующие.
• Функция mallopt() изменяет различные параметры, которые управляют алгоритмом, используемым функцией malloc(). Например, один из таких параметров определяет минимальный объем высвобождаемого пространства, которое должно быть в конце списка свободных блоков, перед тем как используется sbrk() для сжатия кучи. Еще один параметр указывает верхний предел для размера блоков, выделяемых из кучи. Блоки, превышающие этот предел, выделяются с использованием системного вызова mmap() (см. раздел 45.7).
• Функция mallinfo() возвращает структуру, содержащую различные статистические данные о выделении памяти с помощью malloc().
Версии mallopt() и mallinfo() предоставляются многими реализациями UNIX. Но интерфейсы, предоставляемые этими функциями, у всех реализаций различаются, поэтому они не портируются.
7.1.4. Другие методы выделения памяти в куче
Наряду с malloc() библиотека языка C предоставляет ряд других функций для выделения памяти в куче. Они будут описаны в этом разделе.
Выделение памяти с помощью функций calloc() и realloc()
Функция calloc() выделяет память для массива одинаковых элементов.
#include
void *calloc(size_t
Возвращает указатель на выделенную память при успешном завершении или NULL при ошибке
Аргумент numitems указывает количество выделяемых элементов, а аргумент size определяет их размер. После выделения блока памяти соответствующего размера calloc() возвращает указатель на начало блока (или NULL, если память не может быть выделена). В отличие от malloc(), функция calloc() инициализирует выделенную память нулевым значением.
Рассмотрим пример использования функции calloc():
struct myStruct { /* Определение нескольких полей */ };
struct myStruct *p;
p = calloc(1000, sizeof(struct myStruct));
if (p == NULL)
errExit("calloc");
Функция realloc() используется для изменения размера (обычно увеличения) блока памяти, ранее выделенного одной из функций из пакета malloc.
#include
void *realloc(void *
Возвращает указатель на выделенную память при успешном завершении или NULL при ошибке