java.lang.OutOfMemoryError: Map failed

最近遇到這個Exception,發(fā)現(xiàn)不少開源框架在實現(xiàn)快速讀寫文件時,采用的都是FileChannel的map方法,示例如下:

at sun.nio.ch.FileChannelImpl.map0(Native Method) ~[?:1.8.0_40]
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:904) ~[?:1.8.0_40]

這個方法的作用是將文件映射到堆外內(nèi)存中,然后通過讀寫內(nèi)存來實現(xiàn)對文件的快速讀寫。從知乎摘了一張圖。

mmap display
mmap display


問題 & 解決

目前來看,我在使用MapDB和Phoenix時都曾經(jīng)出現(xiàn)過這個Exception,MapDB直接將DB文件映射到堆外內(nèi)存,來達到高效的讀寫;Phoenix在結(jié)果集過大時,需要落地成臨時文件,而這個臨時文件是采用mmap來操作的。

Map Failed 出現(xiàn)的原因有很多:

1. 對于32-bit JVM,由于地址空間是32 bit,2^32=4GB,所以我們能映射的文件大小只有4GB,但實際上因為其他對象同樣需要占用地址空間,所以正常情況下,只能映射1GB左右。   
2. Java程序有默認的maxDirectMemory,即JVM可使用的最大堆外內(nèi)存,稍不注意,就有可能超過并且拋出異常(如在Phoenix數(shù)據(jù)查詢中結(jié)果集過大)。
3. mmap句柄超過了系統(tǒng)默認最大值。系統(tǒng)默認最大值可使用```cat /proc/sys/vm/max_map_count```查看,進程使用句柄數(shù)可使用```cat /proc/$PID/maps | wc -l```查看。每一塊申請的ByteBuffer都對應(yīng)一個mmap句柄,也就是說,如果生成了大量的碎ByteBuffer,那么句柄數(shù)也會急劇增長。而這些句柄的回收是伴隨著ByteBuffer回收的,堆外內(nèi)存的GC需要顯示調(diào)用System.gc來進行。  

解決方式:

1. 若為32-bit JVM,可升級到64-bit,獲得更大的地址空間。
2. 若為64-bit JVM,當超出堆外內(nèi)存不多且使用總內(nèi)存小于32GB時,使用-XX:useCompressedOops來壓縮對象的空間大小。
3. 調(diào)整-XX:maxDirectMemorySize來獲得更多的堆外內(nèi)存。
4. 調(diào)整/proc/sys/vm/max_map_count。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 最近收拾屋子,整理出一大堆酒瓶水瓶硬紙殼甚至還有些木板。我把它們分類放好,酒瓶排好隊,塑料瓶踩扁放大箱子,紙箱子廢...
    荒島黎明7809閱讀 473評論 0 0
  • 巖洞百折似宮闕,獨占塞北第一絕。 奇石滿谷形態(tài)異,兩泉匯流成響河。 秋賞紅葉冬白雪,春觀杏花夏百合。 游人搖指幽徑...
    二斗八閱讀 578評論 1 13
  • 子落楸坪,雨落鴛鴦瓦,與誰邀杯弄清茶? 云飄遠處,豉留伊人手,與誰提筆傳念書? 陽漸西下,人坐清柳堤,與誰執(zhí)手渡黃...
    十亦C閱讀 594評論 3 8