Linux内存映射文件保留了大量物理内存

时间:2010-09-24 16:16:07

标签: linux macos mmap

我遇到了一个问题,这个问题在关于内存映射和Linux下不断增长的内存消耗的多个线程中有所描述。

当我在Linux或MacOS X下打开1GB文件并使用

将其映射到内存时
me.data_begin = mmap(NULL, capacity(me), prot, MAP_SHARED, me.file.handle, 0);

并顺序读取映射内存,我的程序使用越来越多的物理内存,虽然我使用了posix_madvise(甚至在读取过程中多次调用它):

posix_madvise(me.data_begin, capacity(me), MMAP_SEQUENTIAL);

没有成功。 : - (

我试过了:

  • 不同的标志MMAP_RANDOM,MMAP_DONTNEED,MMAP_NORMAL没有成功
  • 在调用mmap之前和之后
  • posix_fadvise(me.file.handle,0,capacity(me),POSIX_FADV_DONTNEED) - >没有成功

在Mac OS X下工作 !!!当我结合

posix_madvise(.. MMAP_SEQUENTIAL)

msync(me.data_begin, capacity(me), MS_INVALIDATE).

常驻内存低于16M(我在16mio步后定期调用msync)。

但在 Linux下无效。有没有人对我在Linux下的问题有想法或成功的故事?

干杯, 大卫

1 个答案:

答案 0 :(得分:8)

Linux内存管理与其他系统不同。关键原则是没有使用的内存是浪费的内存。在许多方面,Linux试图最大限度地提高内存使用率,从而(大部分时间)获得更好的性能。

Linux中并不是“无效”,但它的行为与您预期的有点不同。

当从mmapped文件中提取内存页面时,操作系统必须决定它将释放(或换出)哪些物理内存页面才能使用。它将查找更易于更换的页面(不需要立即写入磁盘),并且不太可能再次使用。

madvice()POSIX调用用于告诉系统应用程序将如何使用这些页面。但正如名称所说,它是一个建议,因此操作系统可以更好地进行分页和交换决策。它既不是政策,也不是订单。

为了演示madvice()对Linux的影响,我修改了我给学生的一个练习。请参阅complete source code here。我的系统是64位的,有2 GB的RAM,现在大约有50%在使用。使用该程序mmap 2 GB文件,按顺序读取并丢弃所有内容。它报告每读取200 MB的RSS使用情况。结果没有madvice()

<juliano@home> ~% ./madvtest file.dat n
     0 :     3 MB
   200 :   202 MB
   400 :   402 MB
   600 :   602 MB
   800 :   802 MB
  1000 :  1002 MB
  1200 :  1066 MB
  1400 :  1068 MB
  1600 :  1078 MB
  1800 :  1113 MB
  2000 :  1113 MB

Linux一直在推迟内存,直到读取大约1 GB。之后,它开始对进程本身施压(因为其他50%的内存由其他进程激活)并稳定到文件末尾。

现在,使用madvice()

<juliano@home> ~% ./madvtest file.dat y
     0 :     3 MB
   200 :   202 MB
   400 :   402 MB
   600 :   494 MB
   800 :   501 MB
  1000 :   518 MB
  1200 :   530 MB
  1400 :   530 MB
  1600 :   530 MB
  1800 :   595 MB
  2000 :   788 MB

请注意,Linux决定只将页面分配给进程,直到它达到大约500 MB,比没有madvice()早得多。这是因为在此之后,当前在内存中的页面似乎比通过此过程标记为顺序访问的页面更有价值。 VMM中有一个阈值,用于定义何时开始从进程中删除旧页面。

您可能会问为什么Linux会将页面分配到大约500 MB并且不会更快停止,因为它们被标记为顺序访问。无论如何系统都有足够的可用内存页面,或者其他驻留页面太旧而无法保留。在将旧页面保留在内存中似乎不再有用,并为运行现在的程序提供更多页面之间,Linux会选择第二个选项。

即使它们被标记为顺序访问,它也只是一个建议。应用程序可能仍希望返回到这些页面并再次阅读它们。或者系统中的另一个应用程序。 madvice()调用只说应用程序本身正在做什么,Linux考虑了更大的图景。