来自ps
输出的三个值 vsize , size 和 rss 中的哪一个适合用于快速内存泄漏检测?出于我的目的,如果一个进程已经运行了几天并且它的内存不断增加那么这就足以说明它正在泄漏内存。我知道最终应该使用像valgrind这样的工具,但它的使用是侵入性的,因此并不总是可取的。
根据我的理解,我写了一段简单的C代码,它基本上分配了1 MiB的内存,释放它然后再分配1 MiB。它也会在每个步骤之前休眠10秒,让我有时间查看ps -p <pid> -ovsize=,size=,rss=
的输出。这是:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#define info(args...) printf(args)
char* bytes(char* str, uint32_t size, uint32_t n)
{
char* unit = "B";
if (n > 1000) {
n /= 1000;
unit = "KB";
}
if (n > 1000) {
n /= 1000;
unit = "MB";
}
snprintf(str, size, "%u %s", n, unit);
return(str);
}
void* xmalloc(size_t size)
{
char msg[64];
size_t max = sizeof(msg);
void *p = NULL;
info("Allocating %s\n", bytes(msg, max, size));
p = malloc(size);
memset(p, '1', size);
return(p);
}
void* xfree(void* p, size_t size)
{
char msg[64];
size_t max = sizeof(msg);
info("Freeing %s\n", bytes(msg, max, size));
free(p);
return(NULL);
}
void nap()
{
const int dur = 10;
info("Sleeping for %d seconds\n", dur);
sleep(dur);
}
int main(void)
{
int err = 0;
size_t kb = 1024;
size_t block = 1024 * kb;
char* p = NULL;
nap();
p = xmalloc(block);
nap();
p = xfree(p, block);
nap();
p = xmalloc(block);
nap();
return(err);
}
现在,ps
每两秒从一个shell脚本运行,该脚本也帮助打印了测量时间戳。它的输出是:
# time vsize size rss
1429207116 3940 188 312
1429207118 3940 188 312
1429207120 3940 188 312
1429207122 3940 188 312
1429207124 3940 188 312
1429207126 4968 1216 1364
1429207128 4968 1216 1364
1429207130 4968 1216 1364
1429207132 4968 1216 1364
1429207135 4968 1216 1364
1429207137 3940 188 488
1429207139 3940 188 488
1429207141 3940 188 488
1429207143 3940 188 488
1429207145 5096 1344 1276
1429207147 5096 1344 1276
1429207149 5096 1344 1276
1429207151 5096 1344 1276
1429207153 5096 1344 1276
根据上面的值,并记住ps(1)
手册页中给出的描述,在我看来,最好的衡量标准是vsize。这种理解是否正确?请注意,手册页说大小是脏页总量的度量,rs是物理内存中页面的数量。这些可能会低于流程使用的总内存。
这些实验是在运行GNU / Linux 3.2.0-4-amd64的Debian 7.8上进行的。
答案 0 :(得分:4)
一般而言,流程的总虚拟大小(vsize
)是流程大小的主要衡量标准。 rss
只是恰好使用真实内存的部分。 size
衡量实际修改了多少页。
持续增加vsize
,具有相对稳定或循环size
和rss
值可能会建议堆碎片或糟糕的堆分配器算法。
不断增加的vsize
和size
,相对稳定的rss
可能表示内存泄漏,堆碎片或糟糕的堆分配器算法。
您必须了解给定程序如何使用内存资源,以便仅使用这些外部过程资源使用量来估计是否存在内存泄漏。
部分内容涉及了解C库malloc()
和free()
例程如何管理堆,包括内部管理活动分配列表可能需要的额外内存,它如何处理堆的碎片,以及它如何将未使用的堆部分释放回操作系统。
例如,您的测试显示了流程的总虚拟大小以及&#34;脏&#34;的数量。它所需的页面,在程序第二次再次分配相同数量的内存时会略微增大。这可能显示malloc()
的一些开销,即它自己的内部数据结构在此之前所需的内存量。如果程序在退出之前完成了另一个free()
和sleep()
,那将会很有趣。修改代码也可能有所帮助,以便在调用sleep()
和malloc()
之间调用memset()
,然后观察ps
的结果。
因此,一个简单的程序应该只需要运行固定数量的内存,或者分配内存来执行特定的工作单元,然后在完成该工作单元后释放所有内存,应该显示一个相对稳定的vsize
,假设它一次不能处理多个工作单元并且有一个“坏”的问题。分配模式会导致堆碎片。
正如您所指出的,像valgrind
这样的工具,以及对程序内部实现的深入了解,对于显示实际的内存泄漏并证明它们完全是程序的责任是必要的。
(顺便说一句,你可能想要稍微简化你的代码 - 特别是不要使用像info()
这样的不必要的宏,并且对于这种类型的例子试图用更大的单位打印值,使用额外的变量进行大小计算等等,也更多的是混淆而不是帮助。太多的printfs也会混淆代码 - 只使用那些你需要的程序来查看程序所处的步骤并查看不是的值在编译时已知。)