GLIBC ( ГЛИБЦ ):отладка утечек памяти:как интерпретировать выходные данные mtrace()
-
03-07-2019 - |
Вопрос
Я пытаюсь отладить проблему с утечкой памяти.Я использую mtrace() чтобы получить трассировку malloc / free / realloc.Я запустил свою программу, и теперь у меня есть огромный файл журнала.Пока все идет хорошо.Но у меня возникли проблемы с интерпретацией файла.Посмотрите на эти строки:
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1502570 0x68
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1502620 0x30
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa80
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1501460 0xa64
Странным в этом является то, что один вызов (тот же обратный адрес) отвечает за 4 распределения.
Еще более странный:
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa2c
…
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa80
Между этими двумя строками блок 0x2aaab43a1700 никогда не освобождается.
Кто-нибудь знает, как это объяснить?Как один вызов может привести к выделению 4 единиц?И как malloc мог вернуть адрес, который уже был выделен ранее?
редактировать 2008/09/30:Скрипт для анализа выходных данных mtrace (), предоставленный GLIBC (mtrace.pl), здесь ничем не поможет.Он просто скажет:Выделите дубликат 0x2aaab43a1700.Но как это могло произойти?
Решение
Функция, выделяющая память, вызывается более одного раза.Адрес вызывающего абонента указывает на код, который выполнил выделение, и этот код просто выполняется более одного раза.
Вот пример на языке Си:
void *allocate (void)
{
return (malloc(1000));
}
int main()
{
mtrace();
allocate();
allocate();
}
Результатом работы mtrace является:
Memory not freed: ----------------- Address Size Caller 0x0000000000601460 0x3e8 at 0x4004f6 0x0000000000601850 0x3e8 at 0x4004f6
Обратите внимание, насколько идентичен адрес вызывающего абонента?Вот почему скрипт, анализирующий mtrace, говорит, что они идентичны, потому что одна и та же ошибка обнаруживается более одного раза, что приводит к нескольким утечкам памяти.
Компиляция с флагами отладки (-g) полезна, если вы можете:
Memory not freed: ----------------- Address Size Caller 0x0000000000601460 0x3e8 at /home/andrjohn/development/playground/test.c:6 0x0000000000601850 0x3e8 at /home/andrjohn/development/playground/test.c:6
Другие советы
Вы смотрите на прямой вывод mtrace, который чрезвычайно запутан и противоречит здравому смыслу.К счастью, существует perl-скрипт (называемый mtrace, найденный в glibc-utils), который может очень легко помочь в синтаксическом анализе этого вывода.
Скомпилируйте свою сборку с включенной отладкой и запустите mtrace следующим образом:
$ gcc -g -o test test.c
$ MALLOC_TRACE=mtrace.out ./test
$ mtrace test mtrace.out
Memory not freed:
-----------------
Address Size Caller
0x094d9378 0x400 at test.c:6
Результатом должно быть лот легче усваивается.
Одно из возможных объяснений заключается в том, что одна и та же функция выделяет разные размеры буфера?Одним из таких примеров является strdup .
Что касается второго вопроса, возможно, что среда выполнения выделяет некоторую "статическую" область очистки, которая не предназначена для освобождения до тех пор, пока процесс не будет завершен.И в этот момент операционная система все равно произведет очистку после завершения процесса.
Подумайте об этом с другой стороны:в Java нет деструкторов и нет гарантий, что финализация когда-либо будет вызвана для какого-либо объекта.
Попробуйте запустить свое приложение под управлением valgrind.Это могло бы дать вам лучшее представление о том, что на самом деле происходит утечка.