2010-09-24 76 views
5

我有一個在多線程中描述的有關內存映射和Linux下不斷增長的內存消耗的問題。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沒有成功
  • posix_fadvise(me.file.handle,0,容量(我),POSIX_FADV_DONTNEED)和前MMAP調用後 - >沒有成功

在Mac OS X !!!當我結合

posix_madvise(.. MMAP_SEQUENTIAL) 
工作

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

駐留存儲器低於16M(I週期性地調用的msync 16mio步驟之後)。

但是根據Linux沒有任何工作。有沒有人對我在Linux下的問題有一個想法或成功的故事?

乾杯, 大衛

+0

它可能也可能不相關,但應該知道:您使用的是32位還是64位系統?你知道你不應該在32位系統中映射1GB? (即使您使用的是64位系統,您也可能會擔心可移植性)。 – Juliano 2010-09-24 18:13:21

+0

所有系統都是64位(帶有64位文件指針和偏移量),我可以成功映射40GB文件。爲了可重複性,我只是將問題歸結爲1GB。 – Dave 2010-09-26 10:17:30

+0

@Sven。有時使用內存映射是不可避免的,例如,當庫調用需要內存區域而不是文件時。所以你的建議是無益的,並沒有回答這個問題。 至於答案,顯然在Linux上MMAP_SEQUENTIAL是非常*破碎*。預讀部分工作,頁面回收部分不工作。唯一的辦法是向Linux提出,實際上這些頁面是很好的候選者是通過取消映射區域(並重新映射)。 – 2015-03-06 00:51:15

回答

8

Linux內存管理是從其他系統不同。關鍵原則是沒有使用的內存會浪費內存。在很多方面,Linux都會嘗試最大限度地利用內存,從而導致(大部分時間)具有更好的性能。

這並不是說「沒有任何工作」在Linux中,但它的行爲有點不同於你的期望。

當從mmapped文件中提取內存頁時,操作系統必須決定它將釋放(或換出)哪些物理內存頁以便使用。它會查找更容易換出的頁面(不需要立即寫入磁盤),並且不太可能再次使用。

madvice()POSIX調用用來告訴系統應用程序如何使用頁面。但正如名稱所示,這是一個建議,以便操作系統更好地進行分頁和交換決策。這既不是政策也不是秩序。

爲了演示madvice()在Linux上的效果,我修改了一個給予我的學生的練習。請參閱complete source code here。我的系統是64位,有2 GB的RAM,現在大約有50%正在使用。使用該程序來映射2 GB文件,按順序讀取並丟棄所有內容。它每讀取200 MB報告RSS使用情況。結果無madvice()

<[email protected]> ~% ./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()

<[email protected]> ~% ./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則考慮更大的圖景。

+0

謝謝Juliano,50%的行爲很有趣。我只是想知道爲什麼沒有辦法強制Linux釋放我再也不會讀取的頁面。相反,它會犧牲文件系統的緩衝區和緩存。 在MacOS X上犧牲這些緩衝區會阻塞系統,直到它完全無法使用。但幸運的是,我們可以通過 * msync(... MS_INVALIDATE)* 來防止在Linux上這似乎是您觀察到的使用madvice防止系統停滯的行爲。 – Dave 2010-09-27 22:50:17

+1

@Dave:認爲沒有必要過早地釋放這些頁面。 Linux不會犧牲緩存和緩衝區,相反,它正是這樣做的。當你從磁盤讀取更多數據時,Linux必須將這些數據帶到內存中。它對從磁盤讀取的內容進行排序,但不是將其視爲「緩存」,而是將其作爲映射該文件的進程的RSS部分的一部分進行計算。當Linux需要再次緩存時,它將釋放映射到該應用程序的那些頁面。你不需要擔心這一點! – Juliano 2010-09-28 04:09:54

+0

@Juliano:認爲MADV_SEQUENTIAL專門告訴系統頁面將通過順序讀取訪問一次。這些頁面是回收的理想選擇。相反,我看到在我的盒子裏,直到達到50%的內存(在這種情況下是32GB),文件緩存才被回收。我發現其他進程的性能正在下降,現在我發現了一種迫使linux不這樣做的嘲諷方式。通過重新映射和映射文件,每1Gb左右。 * DOES *解決了問題,之後我沒有看到其他進程的性能下降。 – 2015-03-06 00:14:28