使用malloc时出现内存泄漏问题

3

我正在编写一个程序来泄露内存(主内存),以测试系统在低系统内存和交换内存下的行为。我们使用以下循环定期运行并泄漏内存。

main(int argc, char* argv[] )  
{
   int arg_mem = argv[1];

        while(1)
        {
          u_int_ptr =(unsigned int*)  malloc(arg_mem * 1024 * 1024);

        if( u_int_ptr == NULL )
           printf("\n leakyapp Daemon FAILED due to insufficient available memory....");

          sleep( arg_time );
        }

}

循环运行一段时间后,打印消息“由于可用内存不足,leakyapp守护进程失败...”。但是当我运行命令“free”时,我可以看到运行此程序对主内存或交换空间没有影响。
我做错了什么吗?
6个回答

8

只有当您实际写入物理内存时,才会将其分配给您的分配。

如果您的内核版本在2.6.23之后,请使用带有MAP_POPULATE标志的mmap()而不是malloc()

u_int_ptr = mmap(NULL, arg_mem * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);

if (u_int_ptr == MAP_FAILED)
    /* ... */

如果您使用的是较旧版本的内核,您需要触碰分配中的每个页面。

我认为最后一行中的“不要”应该被删除 :-) - mtvec
我根据需要修改了我的代码。我声明了一个数组来存储所有的指针。 char * a[1000]; 在while循环中, u_int_ptr = mmap(NULL, arg_mem * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); a[i] = (char*) u_int_ptr; // Touch page *a[i] = 'A'; i++;但是我仍然面临着同样的问题。 - Sirish

3

可能有一些写时复制的优化。我建议实际写一些内容到你正在分配的内存中。


1
发生的情况是malloc从堆中请求argmem * 256页(假设页面大小为4 Kbyte)。堆随后从操作系统请求内存。然而,这只是为新分配的内存块创建页面表条目。除了堆跟踪malloc请求所需的RAM之外,没有实际的物理RAM分配给进程。
一旦进程尝试通过读取或写入其中一个页面来访问这些页面,就会生成页面错误,因为页面表中的条目实际上是悬空指针。然后,操作系统将为进程分配物理页面。只有在这时,您才会看到可用物理内存减少。
由于所有新页面都始终彻底清零,Linux可能会采用“写时复制”策略来优化页面分配。即它可能保持单个页面完全清零,并且当进程尝试从先前未使用的页面读取时,总是分配该页面。只有当进程尝试写入该新页面时,它才会实际从物理RAM分配完全新的页面。我不知道Linux是否真的这样做,但如果它这样做,仅从新页面读取不足以增加物理内存使用率。
所以,你最好的策略是分配你的大块RAM,然后在整个内存中每隔4096字节写入一些内容。

0

ulimit -m -v 命令会输出什么内容?

解释:在任何服务器操作系统上,您都可以限制进程可以分配的资源量,以确保单个失控进程无法使整个机器崩溃。


它显示最大内存大小(kbytes,-m)无限制 虚拟内存(kbytes,-v)无限制 - Sirish
在这种情况下,我的回答没有帮助 :-) - Aaron Digulla

0

根据命令行参数,我猜测您正在使用桌面/服务器操作系统而不是嵌入式系统。

像这样分配内存可能并没有消耗太多RAM。您的内存分配甚至可能没有成功 - 在某些操作系统(例如Linux)中,malloc()即使您请求超过可用内存的更多内存,也可以返回非NULL。

如果不知道您的操作系统以及您要测试的确切内容,很难提出具体建议,但您可能需要查看比malloc()更低级别的内存分配方式,或者控制虚拟内存系统的方法。在Linux上,您可能需要查看mlock()


0

我认为caf已经解释过了。Linux通常配置为允许超额分配内存。您可以分配大块的内存,但实际上只是在做一个记录,表明您的程序需要这么多的内存。直到您尝试写入该内存块时,内核才会尝试找到空闲虚拟内存来满足读/写访问。这有点像航班预订:航空公司通常会过度预订航班,因为总有一定比例的乘客不会出现。

您可以通过使用memset()在分配后写入块来强制提交内存。calloc也应该可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接