2012-09-24 22 views
2

我試圖在READ_WRITE模式下使用Java MappedByteBuffers來映射一個大文件(幾十GB)或一組無數小文件(〜128MB)。這是爲了實現高性能的B樹。在READ_WRITE模式下使用大量MappedByteBuffer減慢Windows 7抓取速度

我的問題是,在我的Windows 8筆記本電腦上配備8GB RAM和JDK 7時,一切都很順利,直到物理內存已滿並且操作系統開始實際將數據寫入文件。在這一點上,Windows慢慢爬行。 I/O似乎完全捱餓任何其他活動。鼠標指針幾乎不能移動,我通常最終不得不強制重新啓動機器。

下面的代碼演示了這個問題:

public static void testMap() throws Exception 
{ 
    MappedByteBuffer[] mbbs = new MappedByteBuffer[512]; 
    for (int i = 0; i < 512; i++) 
    { 
     System.out.printf("i=%d%n", i); 
     RandomAccessFile raf = new RandomAccessFile(String.format("D:/testMap.%d.bin", i), "rw"); 
     mbbs[i] = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128*1024*1024); 
     for (int j = 0; j < 128*1024; j++) { 
      mbbs[i].put(j*1024, (byte)(i*j)); 
     } 
    } 
} 

如果I/O的需要一定的時間,我不介意。過了一段時間,操作系統實際上必須開始將字節寫入文件。但是,在這裏,這個過程基本上使整個操作系統捱餓。我怎樣才能避免這種情況?

+2

認識到在處理稀缺資源時會遇到資源限制很重要。是否有理由需要同時提供512個可用的內存映射文件?根據您的使用情況,您可能會採取多種不同的方法,包括集中稀缺資源(打開文件句柄)。 – allingeek

+0

實際上,我預計文件幾乎是隨機訪問的。這就是爲什麼我希望能夠同時保留所有視圖的映射。當然,這在64位機器上似乎被認爲是可行的做法。例如,請參閱http://stackoverflow.com/questions/9261316/memory-mapped-mappedbytebuffer-or-direct-bytebuffer-for-db-implementation。它在閱讀方面工作得很好,但對寫作並不完全。我懷疑過了一段時間後,任何進程的內存訪問都會迫使操作系統將JVM進程加載的一些髒頁換掉。任何建議,以避免這種情況? – alex137

+0

根據您希望同時訪問的文件數量,合併的解決方案可以很好地工作。使用池式方法,您可以通過改變池大小來調整性能。 無論如何,當系統內存不足時,操作系統將不得不開始交換。這就是整臺機器出現故障的原因。 – allingeek

回答

2

您正在映射512x128x1024x1024字節或64千兆字節,並且您有8千兆字節。所以,你實際上將內存過度提高了8倍。對於閱讀而言,這是可以的,因爲操作系統可能會將頁面錯誤地指向一個充滿空值的頁面,並且所有這些頁面甚至可能是同一頁面。但是當你寫作時,頁面必須被帶入虛擬存在。所以你在摔打。您需要8倍於主存儲器或映射字節緩衝區的數量。

+0

感謝您的評論。我期待操作系統能夠在整個系統崩潰之前足夠聰明地將髒頁面換掉。你看,我沒有過度提交內存:我不介意操作系統做大量的磁盤IO,因爲這個想法是操作系統應該比管理它的緩存的程序更好。順便說一下,即使頁面沒有填充空值(在我的代碼中,幾乎每個頁面都包含一些非空字節),該映射對於閱讀都可以正常工作。操作系統只是觸發IO並管理緩存就好了,這是使用內存映射文件的要點。 – alex137

+0

@ user1695431根據定義,提交10倍的物理內存過量提交。 – EJP

+0

但我不想將這個虛擬內存區域提交給物理內存。如果操作系統只是在程序寫入這些頁面時換出頁面,我很確定。我認爲這是使用內存映射文件的優勢之一:即使文件大於可用物理內存,也能夠像訪問內存一樣訪問文件。此外,它在閱讀中效果很好。所以,我仍然在尋找令人滿意的解決方案來解決我的問題...... – alex137