JVM堆外記憶體問題排查

方丈的寺院發表於2018-07-15

摘要

JVM 堆記憶體一般分析的比較多,本篇談談堆外記憶體問題排查,通常我們需要排查堆外記憶體的原因是系統整個記憶體使用飆高,但是堆內記憶體使用正常。這時候就需要分析堆外記憶體了

堆外記憶體組成

通常JVM的引數我們會配置

-Xms 堆初始記憶體
-Xmx 堆最大記憶體
-XX:+UseG1GC/CMS 垃圾回收器
-XX:+DisableExplicitGC 禁止顯示GC
-XX:MaxDirectMemorySize 設定最大堆外記憶體,預設是-xmx-survivor,也就是基本上和-xmx大小相等
-Xss:每個執行緒的堆疊大小,預設1M
-Xmn: 年輕代大小(eden區+2 survivor)
-XX:newRatio: 4 年輕代與老年代1:4
-XX:survivorRatio: 8Eden區與survivor大小比值

java整個程式佔用的記憶體:
- 堆記憶體
- metaspace(堆內) JDK8使用metaspace來替代了permsize:永久代大小
- 堆外記憶體使用
- 執行緒棧空間

堆外記憶體回收: 堆外記憶體的回收是通過system.gc()來的,依賴於目前的gc機制。
通常是通過DirectByteBuffer物件來分配堆外記憶體,gc的時候就是判斷這個物件是否被引用,來決定是否回收。

問題排查

首先確認堆佔用

  1. jmap 檢視heap記憶體使用情況

    jmap -heap pid

    可以檢視到MetaspaceSize,CompressedClassSpaceSize,MaxMetaSize
    jmap和jdk版本有關係,有些jdk版本會檢視不到記憶體資訊,可以使用jstat來檢視統計資訊

  2. jstat 收集統計資訊

jstat -gc pid 1000
S0C/S0U S1C/S1U EC/EU CCSC/CCSU YGC/YGCT FGC/FCGT GCT
survivor0容量和使用 survivor1容量和使用 Eden jdk8是meta,以前應該是PC,PC young gc次數和耗時 full gc次數和耗時 total gc時間

排除掉heap的問題

分析堆外情況

NMT(native memory tracking)

使用
在JVM引數中新增
-XX:NativeMemoryTracking=[off | summary | detail]

-XX:NativeMemoryTracking=detail

在JVM執行過程中,使用jcmd獲取相關資訊
jcmd pid VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

jcmd pid VM.native_memory detail

baseline個基準,之後會輸出diff引數,來和這個基線版本進行比較,可以兩次的記憶體差
NMT報告會顯示記憶體使用情況

類別 含義
Java Heap 堆大小
Thread 執行緒
Thread Stack 執行緒棧

更多參考:

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr022.html

NMT可以得到執行緒棧大小,排除棧空間影響

pmap 檢視程式記憶體地址空間

pmap -x pid | sort xx

可以結合pmap,和nmt得到記憶體地址空間。和堆外佔用情況了

接下來需要做的就是分析堆外記憶體的內容了。

gdb dump檢視記憶體空間內容

(gdb) dump binary memory ./file BEGIN_ADDRESS END_ADDRESS

將記憶體內容dump到檔案中,就可以檢視到檔案中的內容了。
但是這種方式不直觀,所以可以使用其他工具

  • gperf
    google的,使用gperf2.5即可,網上很多安裝都說一定要安裝libunwind,其實都是瞎抄抄,老版本確實需要,2.5的版本不需要了。

    https://blog.csdn.net/unix21/article/details/79161250
    另外一個注意點就是雖然heap檔案只有1M,但是可以分析出堆外記憶體的大小。
    不過我在實際使用過程中,gperf並沒有分析出實際的堆外記憶體情況,通過pmap可以看出堆外記憶體佔用有幾個G,但是gperf始終只有200M

  • Jemalloc
    https://github.com/jemalloc/jemalloc/releases
    安裝

     ./configurate –enable-prof
    make
    sudo make install

    配置

export LD_PRELOAD=/usr/local/lib/libjemalloc.so 
export MALLOC_CONF=prof:true,lg_prof_interval:31,lg_prof_sample:17,prof_prefix:/output/jeprof

https://github.com/jemalloc/jemalloc/wiki/Getting-Started

最後分析是dubbo,rpc呼叫過程中,有很多的資料傳輸物件,而堆外記憶體大小又沒有限制,導致記憶體持續飆高

這裡寫圖片描述

參考

https://www.cnblogs.com/softidea/p/5267757.html
https://blog.csdn.net/u014459326/article/details/53609885
https://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
http://lovestblog.cn/blog/2015/05/07/system-gc/
https://blog.csdn.net/kringpin_lin/article/details/26211119
https://blog.csdn.net/jicahoo/article/details/50933469
http://tinylab.org/the-builtin-heap-profiling-of-jemalloc/

相關文章