Будем искать через mdb. Что бы иметь возможность это сделать, нужно что бы приложение было запущено в режиме debug. Если в самом приложении отсутствует такая возможность, тогда нужно включить его в окружении и потом запустить приложение:
$ export LD_PRELOAD=libumem.so $ export UMEM_DEBUG=default $ export UMEM_LOGGING=transaction
Переменная окружения UMEM_DEBUG может принимать такие значения:
- adi_precise
Enable precise mode ADI trapping where memory write errors are caught a few instructions after the exact instruction is executed. This has an overall performance overhead, but is more accurate at determining the exact point that an ADI fault occurred. The default is to use disrupting mode traps. For more information, see the adi(7) manual page.
- audit[=frames]
Этот параметр позволяет записывать информацию аудита, включая идентификатор потока, отметку времени с высоким разрешением и трассировку стека для последнего действия (выделения или освобождения) при каждом выделении. Если включено ведение журнала транзакций (см. UMEM_LOGGING), эта информация аудита также регистрируется.
Параметр frames устанавливает количество кадров стека, записанных в структуре аудита. Верхняя граница для фреймов определяется реализацией. Если запрашивается большее значение, вместо него используется верхняя граница.
Если frame не указан или не является целым числом, используется значение по умолчанию 15.
Эта опция также включает опцию guards
- contents[=count]
Если аудит и ведение журнала содержимого (см. UMEM_LOGGING) включены, то регистрируются первые байты счетчика каждого буфера, когда они освобождаются. Если буфер короче, чем число байтов, то он регистрируется полностью.
Если счетчик не указан или не является целым числом, используется значение по умолчанию 256.
- default
Эта опция эквивалентна одновременно включенным audit,contents,guards
- guards
Эта опция позволяет заполнять выделенные и освобожденные буферы специальными шаблонами, чтобы помочь обнаружить использование неинициализированных данных и ранее освобожденных буферов. Она также включает 8-байтовую красную зону после каждого буфера, который содержит 0xfeedfacefeedfaceULL.
Когда объект освобождается, он заполняется 0xdeadbeef. Когда объект выделен, шаблон 0xdeadbeef проверяется и заменяется на 0xbaddcafe. Красная зона проверяется каждый раз, когда буфер выделяется или освобождается.
Для кэшей с конструкторами или деструкторами или с обоими типами umem_cache_alloc (3MALLOC) и umem_cache_free (3MALLOC) соответственно применяют конструктор и деструктор кэша вместо кэширования созданных объектов. Наличие assert (3C) в деструкторе, проверяющем, что буфер находится в сконструированном состоянии, может использоваться для обнаружения любых объектов, возвращенных в неправильном состоянии. Смотрите umem_cache_create (3MALLOC) для деталей.
- verbose
Библиотека записывает описания ошибок в стандартную ошибку перед прерыванием. Эти сообщения не локализованы.
Переменная окружения UMEM_LOGGING может принимать такие значения (если нужно несколько, просто перечисляем их через запятую):
- transaction[=size]
Если установлен параметр audit (см. UMEM_DEBUG), в этот журнал заносятся структуры аудита из предыдущих транзакций.
- contents[=size]
Если установлена опция audit, содержимое объектов записывается в этот журнал по мере их освобождения.
Если опция отладки contents не была установлена, то сохраняется 256 байтов каждого освобожденного буфера.
- fail[=size]
Записи заносятся в этот журнал для каждого неудачного размещения.
После того, как описали опции debug’a, вернёмся собственно к самому процессу поиска утечек.
Если процесс уже запущен, то присоединяемся к нему и запускаем встроенную команду findleeks:
# mdb -p `pgrep sstored` > ::findleaks -d mem_alloc_16 leak: 71875583 buffers, 16 bytes each, 1150009328 bytes total ADDR BUFADDR TIMESTAMP THREAD CACHE LASTLOG CONTENTS 1ffd1f4cccc190 1ffd1f4cca8c70 247bbaad78a0cf 9 1ffd1f8d5d0028 0 0 libumem.so.1`umem_cache_alloc+0x158 libumem.so.1`umem_alloc+0xc0 libumem.so.1`malloc+0xd4 sstored`malloc+0x4c libc.so.1`strdup+0xc sspc_proc_scan+0x198 sspc_update+0x8c libc.so.1`_lwp_start
Так же можно запустить и непосредственно из mdb (для анализа core-файлов, тоже применяется конструкция mdb core.970):
# /usr/bin/mdb ./my_leaky_program > ::sysbp _exit > ::run mdb: stop on entry to _exit mdb: target stopped at: libc.so.1`exit+0x14: ta 8 mdb: You've got symbols! mdb: You've got symbols! Loading modules: [ ld.so.1 libumem.so.1 libc.so.1 ] > ::findleaks CACHE LEAKED BUFCTL CALLER 0002c508 1 00040000 main+4 ---------------------------------------------------------------------- Total 1 buffer, 24 bytes > 00040000::bufctl_audit ADDR BUFADDR TIMESTAMP THR LASTLOG CONTENTS CACHE SLAB NEXT DEPTH 00040000 00039fc0 3e34b337e08ef 1 00000000 00000000 0002c508 0003bfb0 00000000 5 libumem.so.1`umem_cache_alloc+0x13c libumem.so.1`umem_alloc+0x60 libumem.so.1`malloc+0x28 main+4 _start+0x108
Как видим, утечки памяти есть. Мы даже попробовали проанализировать “глубже”, через bufctl_audit.
Если по какой-то причине, там пусто, можно дополнительно запустить ::umem_verify, ::umalog, ::walk leak, ::walk leakbuf
> ::umem_verify
Cache Name Addr Cache Integrity
umem_magazine_1 fe826010 clean
umem_magazine_3 fe826390 clean
umem_magazine_7 fe826710 clean
umem_magazine_15 fe826a90 clean
umem_magazine_31 fe827010 clean
umem_magazine_47 fe827390 clean
umem_magazine_63 fe827710 clean
umem_magazine_95 fe827a90 clean
umem_magazine_143 fe828010 clean
umem_slab_cache fe828390 clean
umem_bufctl_cache fe828710 clean
umem_bufctl_audit_cache fe828a90
clean
umem_alloc_1152 8098a90 1 corrupt buffer
Для просмотра всех доступных команд для debug’a памяти, можно воспользоваться
> ::dmods -l libumem.so.1
Из наиболее интересных, я бы отметил следующие:
- umem_verify – повреждена ли память, которая была выделена под конкретное приложение
- umalog – повреждена ли память, которая была выделена под конкретное приложение и в данный момент она освобождена
Так же хотелось бы рассмотреть опции самого findleaks:
- “-d” – детальный вывод каждой утечки
- “-f” – сбросить кеш
- “-v” – расширенный вывод
- “-U” – вывод потенциальных утечек MMAP