Thursday, June 5, 2008

Использование dmalloc

Так как использовать dmalloc не так просто, то записать основные принципы на будущее не бесполезно. Итак, dmalloc линкуется статически, например, так:
.ifdef DMALLOC
CFLAGS+=    -DDMALLOC -DDMALLOC_FUNC_CHECK
LIBS+=    -ldmalloc
.endif

Далее, самый простой способ использовать библиотеку:
определяем функции malloc и free, чтобы иметь представление, из какой строчки кода они вызываются:
#ifdef DMALLOC
#include <dmalloc.h>
#define mymalloc(x) dmalloc_malloc(__FILE__, __LINE__, (x), DMALLOC_FUNC_MALLOC, 0, 1)
#define myrealloc(x, y) dmalloc_realloc(__FILE__, __LINE__, (x), (y), DMALLOC_FUNC_REALLOC, 0, 1)
#define myfree(x) dmalloc_free(__FILE__, __LINE__, (x), DMALLOC_FUNC_FREE)
#define mystrdup(x) dmalloc_strndup(__FILE__, __LINE__, (x), strlen((x)), 1)
#else
#define mymalloc(x) malloc((x))
#define myrealloc(x, y) realloc((x), (y))
#define myfree(x) free((x))
#define mystrdup(x) strdup((x))
#endif

Далее в коде пользуемся только этими функциями для работы с памятью.
Для инициализации библиотеки можно пользоваться переменными окружения. Но в ряде случаев это не работает (cgi, su и прочее). Поэтому я решил делать инициализацию так:

#ifdef DMALLOC
    char dmalloc_log[PATH_MAX];
    snprintf (dmalloc_log, sizeof (dmalloc_log), "debug=0x4f47d03,log=%s/dmalloc-%%p.log", DMALLOC_LOG_PATH);
    dmalloc_debug_setup (dmalloc_log);
#endif

Лог файлы создаются автоматически, DMALLOC_LOG_PATH - это каталог, куда должна быть разрешена запись пользователю, из-под которого запускается интересующая нас программа.

Логирование неосвобожденной памяти тоже лучше выполнять самому, чтобы потом не бояться потерять информацию при падении программы где-то. На мой взгляд, лучше всего использовать марки:
в начале секции кода, где может утекать память ставим:
#ifdef DMALLOC
        unsigned int mark;
        mark = dmalloc_mark();
#endif
в конце секции:
#ifdef DMALLOC
          dmalloc_log_changed(mark,
                            1 /* log unfreed pointers */,
                            0 /* do not log freed pointers */,
                            1 /* log each pnt otherwise summary */);
#endif

В логе имеем что-то вида
1212677815: 289299: Dumping Not-Freed Pointers Changed Since Mark 289178:
1212677815: 289299:  memory table is empty
Или же указатели на память:

1212677788: 288383:  not freed: '0x80144af88|s1' (24 bytes) from 'unknown'
1212677788: 288383:  not freed: '0x80144afc8|s5' (40 bytes) from 'unknown'
1212677788: 288383:  not freed: '0x80144be88|s1' (24 bytes) from 'unknown'
1212677788: 288383:  not freed: '0x80144bec8|s1' (40 bytes) from 'unknown'

Можно уронить процесс в корку (kill -SEGV, например) и посмотреть эти адреса в gdb:
(gdb) x/40c 0x80144bec8

2 comments:

  1. А имеет ли смысл сейчас использовать dmalloc? imho Valgrind и Google Performance Tools имеют более богатый функционал
    у меня на сайте есть статья про использование разных средств поиска утечек памяти и т.п. вещей

    ReplyDelete
  2. Я не очень верю в valgrind под FreeBSD (хотя, говорят, как-то работает). Ну а использую, потому что привык, еще в Джете.

    ReplyDelete