我试图找出进程中什么消耗了大量内存,因此我尝试阅读/proc/pid/smaps
(其中 pid 是进程的 pid)。
令我困惑的是,有些条目没有名字。例如:
4805d000-4805e000 rwxp 0001d000 00:0b 19674210 /lib/ld-2.6.so
Size: 4 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
4805e000-4805f000 ---p 00000000 00:00 0
Size: 4 kB
Rss: 0 kB
Pss: 0 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
4805f000-4885e000 rwxp 00000000 00:00 0
Size: 8188 kB
Rss: 8188 kB
Pss: 8188 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8188 kB
Referenced: 8188 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
上面,第一个条目有 name /lib/ld-2.6.so
,但第二个和第三个条目没有任何名称。那么,那些无名条目是什么?如何找出哪个库创建了它们?
出于好奇,还有什么(除了 valgrind 之外)可以尝试找出程序中什么消耗了内存吗?
在深入研究内核代码后,我发现这些条目确实无法映射到任何文件(fs/proc/task_mmu.c)。但问题仍然存在:它们是什么? mmap() 作为分配内存的一种方式?
答案1
可以通过足够大的创建无名区域malloc
:
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int *ip;
char *before, *after;
asprintf(&before, "cat /proc/%d/smaps > before", getpid());
asprintf(&after, "cat /proc/%d/smaps > after", getpid());
system(before);
ip = malloc(9999999);
if (!ip) abort();
system(after);
return 0;
}
如图所示
$ CFLAGS=-g make ilikebigmallocs
cc -g ilikebigmallocs.c -o ilikebigmallocs
$ ./ilikebigmallocs
$ diff before after
64a65,80
> 7f97425ac000-7f9742f36000 rw-p 00000000 00:00 0
> Size: 9768 kB
> Rss: 4 kB
...
所以至少你的一些区域可能是由malloc
或类似的东西创建的(在幕后称为mmap
)。strace
(或sysdig
) 可以记录这些:
$ strace -e trace=memory -o blah ./ilikebigmallocs
$ awk '/^mmap/{print $NF}' blah
0x7fc6193b1000
0x7fc6193a6000
...
$ grep 7fc6193b1000 after
7fc6193b1000-7fc6193b2000 rw-p 00000000 00:00 0
$
我想您可以使用gdb
malloc 跟踪器或其他方法来解决mmap
内存饥饿进程中特定代码的特定备份...