java9 堆外内存_java堆外内存泄漏排查
當(dāng)考慮Java中的內(nèi)存泄漏時(shí),我們通常會考慮Java堆泄漏,即在堆中分配的對象沒有被垃圾收集。這是我在處理一臺服務(wù)器內(nèi)存泄漏時(shí)的想法,但我即將經(jīng)歷的遠(yuǎn)超出我的想象。
癥狀:運(yùn)行Vertx應(yīng)用程序(沒有交換分區(qū))的生產(chǎn)服務(wù)器被Linux內(nèi)存不足kill掉(操作系統(tǒng)機(jī)制,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存緊張的情況時(shí)釋放內(nèi)存)崩潰。
因?yàn)樗巧a(chǎn)服務(wù)器,所以我認(rèn)為可以讓我們使用堆轉(zhuǎn)儲和MAT來檢查發(fā)生了什么,并嘗試找出誰在消耗這么多內(nèi)存。
結(jié)果令人驚訝,java堆是合理的,遠(yuǎn)遠(yuǎn)少于進(jìn)程內(nèi)存的足跡。有什么東西侵蝕了我的內(nèi)存,我不知道那是什么。
我的出發(fā)點(diǎn)是在home目錄中創(chuàng)建的java致命錯(cuò)誤日志,所以我開始研究這些日志。您可以在下面的頁面中關(guān)于java致命錯(cuò)誤日志的信息:致命錯(cuò)誤日志致命錯(cuò)誤日志可以提供很多有價(jià)值的信息并節(jié)省時(shí)間,因此我建議您仔細(xì)閱讀。致命錯(cuò)誤日志顯示堆大小小于2G,但進(jìn)程正在增長到大約3-4G字節(jié),這是怎么回事?
Java進(jìn)程包含以下內(nèi)存空間:
堆-分配對象的位置。
線程堆棧-包含所有線程堆棧。
Metaspace-包含元數(shù)據(jù)類(替換Java7和更早版本中的PermGen)。
代碼緩存-JIT編譯器代碼緩存。
堆緩沖池不足。
操作系統(tǒng)內(nèi)存-本機(jī)操作系統(tǒng)內(nèi)存。
我用了命令:
jmap -heap [pid]
它打印了JVM堆大小的摘要,還顯示了堆大小約為1.5GByte。
我檢查了元空間的大小,但只有幾兆字節(jié)。也許代碼緩存是問題所在?我再次檢查了致命錯(cuò)誤日志,我看到只有大約20M。我得出的結(jié)論是,可能我有本機(jī)內(nèi)存泄漏即-XX:NativeMemoryTracking=detail,然后使用jcmd實(shí)用程序(包含在JDK中)檢查本機(jī)內(nèi)存。在下一頁中閱讀有關(guān)NMT的更多信息:NMT結(jié)果包含以下內(nèi)容:
Internal (reserved=1031767KB, committed=1031767KB)
(malloc=1031735KB #7619)
(mmap: reserved=32KB, committed=32KB)
我發(fā)現(xiàn)JVM有大約1Gbyte大小的內(nèi)存。現(xiàn)在我確信我有
我發(fā)現(xiàn)有巨大的malloc(操作系統(tǒng)內(nèi)存分配調(diào)用)內(nèi)存分配,但我仍然不知道是什么原因造成的。我試著用gdb處理內(nèi)存轉(zhuǎn)儲,但效果不好,我得出的結(jié)論是它可能不會有用,所以我搜索了Linux內(nèi)存泄漏檢測工具。我有幾個(gè)候選人:
Valgrind
malloc_tracer
前兩個(gè)由于某些原因不起作用,所以嘗試了人們推薦的jemalloc。我在應(yīng)用程序啟動腳本中添加了以下行:
MALLOC_CONF=prof_leak:true,prof_final:true,lg_prof_interval:30,lg_prof_sample:17 \
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 [jre path]/jre/bin/java [app parameters]
一開始jemalloc不起作用,我不得不用configure參數(shù)-enable prof重新編譯它,然后它就開始工作了。關(guān)閉應(yīng)用程序后,jemalloc在工作目錄中創(chuàng)建了reproof文件。
[jemalloc install dir]/bin/jeprof --show_bytes --pdf ‘[jre path]/jre/bin/java' [jeprof file] > [pdf output file name]
jemalloc分析表明,使用malloc os調(diào)用分配內(nèi)存的“Unsafe_AllocateMemory”存在嚴(yán)重泄漏。我原以為我現(xiàn)在就能得到答案,但顯然我錯(cuò)了。我在谷歌上搜索了一下,發(fā)現(xiàn)不安全的分配內(nèi)存可能與名為sun.misc.Unsafe是執(zhí)行本機(jī)內(nèi)存分配的JDK私有類,正如它的名稱所表明的那樣,它是不安全的(Oracle計(jì)劃在java9中刪除這個(gè)類,但最終它仍保留在不受支持的模塊中)。我搜索了應(yīng)用程序代碼,但沒有找到它的任何用法,我假設(shè)它可能是應(yīng)用程序的一些庫使用的。主要嫌疑人是Netty,Netty是Vertx使用的網(wǎng)絡(luò)庫。Netty提供了很好的性能,但它使用本機(jī)內(nèi)存分配來實(shí)現(xiàn)這一點(diǎn)。在Netty源代碼中挖掘發(fā)現(xiàn)它正在使用`sun.misc.Unsafe`分配本機(jī)內(nèi)存池。Netty包含內(nèi)存泄漏檢測機(jī)制,因此我嘗試使用Netty參數(shù):
-Dio.netty.leakDetection.level=advanced But that dind't supply any output.
我試著通過使用其他netty參數(shù)(沒有很好的文檔)來限制netty:
-Dio.netty.noPreferDirect=true
-Dio.netty.allocator.type=unpooled
-Dio.netty.maxDirectMemory=0
但這也不管用。
經(jīng)過多次嘗試,我最終發(fā)現(xiàn)直接內(nèi)存分配可以通過以下jvm參數(shù)來限制:
-XX:MaxDirectMemorySize=[max memory]
在深入研究jvm之后,我終于找到了解決方案。我學(xué)到了很多關(guān)于jvm機(jī)制和內(nèi)存空間的知識。
總結(jié)
以上是生活随笔為你收集整理的java9 堆外内存_java堆外内存泄漏排查的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C--数据结构--树的学习
- 下一篇: 皂基真的不如氨基酸洗面奶吗?