编辑:请推荐一些实际的工具,手动打印printf或手动计算内存分配是不够的。此外,转储init核心并在其中探索并不是一个十分可行的选择。
更新1:valgrind无法工作。通过将内核命令行上的/sbin/init替换为适当的valgrind + init命令似乎也不可行,因为它尝试访问/proc以获取smaps的自身信息,但在运行init之前这些信息还不可用。
更新2:dmalloc也无法工作(在ARM上无法编译)。
malloc
和free
,然后检查日志以寻找模式。
ld
提供了一个非常棒的功能可以在这里发挥作用。
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "__wrap_symbol". Any undefined reference to "__real_symbol" will be resolved to symbol.
This can be used to provide a wrapper for a system function. The wrapper function should be called "__wrap_symbol". If it wishes to call the system function, it should call "__real_symbol".
Here is a trivial example:
void * __wrap_malloc (size_t c) { printf ("malloc called with %zu\n", c); return __real_malloc (c); }
If you link other code with this file using --wrap malloc, then all calls to "malloc" will call the function "__wrap_malloc" instead. The call to "__real_malloc" in "__wrap_malloc" will call the real "malloc" function.
You may wish to provide a "__real_malloc" function as well, so that links without the --wrap option will succeed. If you do this, you should not put the definition of "__real_malloc" in the same file as "__wrap_malloc"; if you do, the assembler may resolve the call before the linker has a chance to wrap it to "malloc".
这里需要明确一下这个功能的用处。
操作步骤如下:
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
)代码。LD_FLAGS
--wrap=malloc
, --wrap=free
链接。现在,无论何时Upstart调用malloc
,该符号都会神奇地解析为您的新符号__wrap_malloc
。美妙的是,由于它发生在链接时,因此对编译代码来说完全透明。这就像shimming或instrumenting,没有任何混乱。malloced
和addr
。--wrap=symbol
功能不适用于实际上是宏的函数名。所以要小心#define malloc nih_malloc
。如果这是libnih所做的,您需要使用--wrap=nih_malloc
和__wrap_nih_malloc
。--wrap=symbol
只能用于修改初始化符号。它不会(也不能)影响库的其他用户。此外,使用 --wrap=symbol
将 libnih 包装在 init 中尽可能地无痛。这就是 --wrap=symbol
的发明目的。有关更多详细信息,请参见我的更新。 - deft_code您可以通过挂钩malloc/free调用并计算每次分配和释放的字节数,来自行检测内存分配情况。
你可以尝试将你的upstart版本与Google's TCMalloc链接起来。它自带一个堆检查器。
堆检查器有两种启用方式:
HEAPCHECK
设置为{ normal | strict | draconian }中的一种。HEAPCHECK
设置为local
,并使用HeapProfileLeakChecker
对象手动检查代码。但我不知道如何为init设置环境变量。
你可以尝试在进程上运行pmap并检查哪些内存段正在增长。这可能会让你对是什么在消耗内存有一些想法。通过一些脚本编写,这个过程几乎可以自动化。
在以前的工作中,我实际上编写了一个脚本,它会在一组运行进程上每隔t秒拍摄n个pmap快照。该输出被馈送到一个perl脚本中,该脚本识别更改大小的段。我用它来定位商业代码中的几个内存泄漏。[我想分享这些脚本,但它们受到以前雇主的知识产权(版权)保护。]