Upstart init - это утечка памяти, как вы ее отлаживаете? - PullRequest
6 голосов
/ 08 октября 2010

У меня утечка памяти в процессе инициализации Upstart (pid 1), какие у меня есть варианты отладки?

РЕДАКТИРОВАТЬ: Предложите мне несколько реальных инструментов для этого, вручнуюразмещение printfs или вычисление памяти вручную не приведет к сокращению.Кроме того, выгрузка ядра инициализации и осмотр вокруг этого не является возможным вариантом.

UPD1: valgrind не работает.Замена / sbin / init в командной строке ядра правильным valgrind + init magic, похоже, не вариант, так как он пытается получить доступ к / proc для себя для smaps, но он недоступен до запуска init.

UPD2: dmalloc тоже не работает (не компилируется в ARM).

Ответы [ 5 ]

8 голосов
/ 11 октября 2010

Решением для бедняков было бы просто регистрировать каждый звонок malloc и free, затем прочесывать журналы и искать шаблон.

ld обеспечивает удивительныйфункция, которая может помочь здесь.

--wrap=symbol

Используйте функцию-обертку для символа.Любая неопределенная ссылка на символ будет преобразована в «__wrap_symbol».Любая неопределенная ссылка на «__real_symbol» будет преобразована в символ.

Это можно использовать для предоставления оболочки для системной функции.Функция-обертка должна называться "__wrap_symbol".Если он хочет вызвать системную функцию, он должен вызвать «__real_symbol».

Вот простой пример:

void *
__wrap_malloc (size_t c)
{
   printf ("malloc called with %zu\n", c);
   return __real_malloc (c);
}

Если вы связываете другой код с этим файлом с помощью --wrap malloc, тогда все вызовы "malloc" будут вызывать функцию "__wrap_malloc".Вызов «__real_malloc» в «__wrap_malloc» вызовет настоящую функцию «malloc».

Вы также можете предоставить функцию «__real_malloc», чтобы ссылки без параметра --wrap выполнялись успешно.Если вы сделаете это, вы не должны помещать определение «__real_malloc» в тот же файл, что и «__wrap_malloc»;если вы это сделаете, ассемблер может разрешить вызов до того, как у компоновщика появится возможность перевести его в «malloc».


Обновление

Просто чтобы было ясноо том, как это полезно.

  • Добавить пользовательский файл в сборку Upstart.

Примерно так:

void*__wrap_malloc( size_t c )
{
   void *malloced = __real_malloc(c);
   /* log malloced with its associated backtrace*/
   /* something like: <malloced>: <bt-symbol-1>, <bt-symbol-2>, .. */
   return malloced
}

void __wrap_free( void* addr )
{
   /* log addr with its associated backtrace*/
   /* something like: <addr>: <bt-symbol-1>, <bt-symbol-2>, .. */
   __real_free(addr);
}
  • Перекомпилируйте выскочку с символами отладки (-g), чтобы вы могли получить некоторые хорошие следы.Вы по-прежнему можете оптимизировать (-O2/-O3) код, если хотите.

  • Link Upstart с дополнительными LD_FLAGS --wrap=malloc, --wrap=free.
    Теперь в любом месте вызовы Upstartmalloc символ будет волшебным образом преобразован в ваш новый символ __wrap_malloc.Прекрасно, что все это прозрачно для скомпилированного кода, как это происходит во время соединения.
    Это похоже на мерцание или инструментирование без какого-либо беспорядка.

  • Запустите перекомпилированный Upstart как обычно, пока не убедитесь, что произошла утечка.

  • Просмотрите журналы на предмет несоответствия malloced s и addr s.

Несколько замечаний:

  • Функция --wrap=symbol не работает с именами функций, которые на самом деле являются макросами.Так что следите за #define malloc nih_malloc.Это то, что libnih нужно использовать вместо --wrap=nih_malloc и __wrap_nih_malloc.
  • Использовать встроенные функции обратного отслеживания gcc * .
  • Только все эти изменениявлияет на перекомпилированный исполняемый файл Upstart.
  • Вместо этого вы можете записать журналы в базу данных sqlite, что может упростить поиск несоответствий malloc и освобождений.
  • вы можете сделать так, чтобы вы записывали в журнал оператор вставки SQL, а затем просто вставляли их в базу данных посмертно для дальнейшего анализа.
2 голосов
/ 11 октября 2010

Вы также можете использовать init без изменений, но создать оболочку, которая устанавливает переменную среды MALLOC_CHECK в 1 или выше . Это позволит вам увидеть некоторую диагностику распределения памяти.

Вариант состоит в том, чтобы немного изменить исходный код инициализации, чтобы установить саму переменную среды раньше, чем она начнет использовать malloc.

Вы также можете по предложению AmineK добавить код отладки в сам исходный код инициализации.

2 голосов
/ 11 октября 2010

Вы можете самостоятельно распределить память, перехватывая вызовы malloc / free и подсчитывая количество байтов, которые вы выделяете и каждый раз освобождаете.

0 голосов
/ 14 октября 2010

Как насчет запуска pmap в процессе и изучения того, какие сегменты памяти растут. Это может дать вам некоторое представление о том, что ест память. Небольшой сценарий может сделать этот процесс почти автоматическим **.

** В прошлой жизни я на самом деле написал сценарий, который будет делать n снимков pmap для набора запущенных процессов с интервалом t секунд. Вывод этого был передан в Perl-скрипт, который идентифицировал сегменты, которые изменили свой размер. Я использовал его, чтобы обнаружить несколько утечек памяти в каком-то коммерческом коде. [Я хотел бы поделиться сценариями, но они защищены авторским правом предыдущего работодателя.]

  • John
0 голосов
/ 11 октября 2010

Вы можете попробовать связать свою версию выскочки с Google TCMalloc .Он поставляется со встроенным средством проверки кучи .

Средство проверки кучи можно включить двумя способами:

  • установить переменную окружения HEAPCHECK на один изнормальный |строгий |draconian}.
  • установить HEAPCHECK в local и проверить код вручную с HeapProfileLeakChecker объектами.

Я не знаю, как установить переменную окружения для initоднако.

...