free()是否取消映射进程的内存?


8

我正在Linux 2.6.16内核上运行C程序。我认为程序中没有内存泄漏,但是经过某些操作,程序的内存消耗保持稳定,并且不会减少。我使用“ ps v”命令监视程序的RSS值。

valgrind massif工具显示在我的进程中mmap分配了很大一部分堆。但是根据代码,这些分配应该在操作完成后释放。是否因为释放的内存仍被映射和/或仍对进程的RSS值起作用?

任何见解将不胜感激!

以下是valgrind massif报告中的片段。注意,我已经为massif工具打开了--pages-as-heap选项,以测量程序使用的所有内存。

--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
 85 701,483,989,262      173,576,192      173,576,192             0            0
 86 704,352,949,469      173,367,296      173,367,296             0            0
 87 707,582,275,643      173,367,296      173,367,296             0            0
 88 710,536,145,814      173,367,296      173,367,296             0            0
100.00% (173,367,296B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc.
->53.40% (92,581,888B) 0x649248B: mmap (in /lib64/tls/libc.so.6)
| ->41.13% (71,303,168B) 0x6446D85: _int_malloc (in /lib64/tls/libc.so.6)
| | ->39.31% (68,157,440B) 0x6448D62: calloc (in /lib64/tls/libc.so.6)
......[my own functions are omitted]
->35.28% (61,157,376B) 0x400F51B: mmap (in /lib64/ld-2.3.3.so)
| ->28.81% (49,954,816B) 0x4004CE8: _dl_map_object_from_fd (in /lib64/ld-2.3.3.so)
| | ->28.81% (49,954,816B) 0x400636B: _dl_map_object (in /lib64/ld-2.3.3.so)
| |   ->18.89% (32,755,712B) 0x400AB42: openaux (in /lib64/ld-2.3.3.so)
| |   | ->18.89% (32,755,712B) 0x400AF7C: _dl_catch_error (in /lib64/ld-2.3.3.so)
| |   |   ->18.89% (32,755,712B) 0x4009FCF: _dl_map_object_deps (in /lib64/ld-2.3.3.so)
| |   |     ->18.89% (32,755,712B) 0x40021FD: dl_main (in /lib64/ld-2.3.3.so)
| |   |       ->18.89% (32,755,712B) 0x400E7F6: _dl_sysdep_start (in /lib64/ld-2.3.3.so)
| |   |         ->18.89% (32,755,712B) 0x4001477: _dl_start (in /lib64/ld-2.3.3.so)
| |   |           ->18.89% (32,755,712B) 0x4000CF6: ??? (in /lib64/ld-2.3.3.so)
| |   |             ->18.89% (32,755,712B) 0x0: ???
| |   |               ->18.89% (32,755,712B) 0x7FF0003D5: ???
| |   |                 ->18.89% (32,755,712B) 0x7FF0003E4: ???
| |   |
......

为什么不使用munmapmunmap(2)
Mikel 2012年

您正在使用共享库吗?您能否提供valgrind以及的输出的相关部分/proc/<PID>/maps
Mikel 2012年

因为glibc malloc和free具有实现,所以我们不使用munmap。是,使用共享库。为什么这么重要?valgrind报告的相关部分已添加到主要问题中。
米歇尔2012年


@michelle我以为你是在打电话mmap。但是现在我想我明白了:您正在呼叫malloc/ calloc,并且正在呼叫mmap
Mikel 2012年

Answers:


5

C库函数free()可以但不必将内存返回给内核。

一些实现是malloc()通过sbrk()系统调用在“堆”和其他未使用的地址空间(“系统中断”)之间移动边界,然后释放那些较大分配中的较小部分。如果不重新分配每个较小的块,free()就无法真正将内存返回给操作系统。

相同的原因适用于malloc()不使用sbrk(2),但可能使用mmap("/dev/zero")或其他方式的实现。我找不到引用,但我似乎记得,一个或另一个BSD都使用mmap()这种方式来获取内存页面。但是,free()除非程序重新分配了每个子分配,否则无法将页面返回到操作系统。

一些malloc()实现确实将内存返回给系统:ChorusOS(?)显然做到了。目前尚不清楚是否移动了系统中断或munmap()'ed页面。

这是一篇有关内存分配器的论文,该论文通过“向虚拟内存管理器主动放弃免费页面”来提高性能。 幻灯片放映,讨论分配器。


我了解free()不会将内存返回给OS。但是free()是否取消映射内存,或者该内存是否仍由glibc内存分配器映射?
米歇尔2012年

“ free()不能将页面返回到操作系统,除非程序重新分配了每个子分配。” 我不太明白这一点。您能解释一下“子分配”吗?
米歇尔2012年

1
@michelle:假设页面大小为4192字节。程序调用malloc(4186),然后调用malloc(8)。该程序已分配了所有页面。程序在4186字节分配上调用free()。free()无法取消映射页面,因为尚未对8字节分配进行free()处理。
布鲁斯·埃迪格

这就说得通了。谢谢布鲁斯。所以我的猜测是,当页面仍被映射时,尽管已释放了其中的一些数据,但valgrind测量仍将其考虑在内。正确?
米歇尔2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.