一般JVM的參數咱們會配置java
-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大小比值git
java整個進程佔用的內存:
- 堆內存
- metaspace(堆內) JDK8使用metaspace來替代了permsize:永久代大小
- 堆外內存使用
- 線程棧空間github
堆外內存回收: 堆外內存的回收是經過system.gc()來的,依賴於目前的gc機制。
一般是經過DirectByteBuffer對象來分配堆外內存,gc的時候就是判斷這個對象是否被引用,來決定是否回收。緩存
-XX:InitialCodeCacheSize=64M \
-XX:CodeCacheExpansionSize=1M \
-XX:CodeCacheMinimumFreeSpace=1M \
-XX:ReservedCodeCacheSize=200M \
-XX:MinMetaspaceExpansion=1M \
-XX:MaxMetaspaceExpansion=8M \
-XX:MaxDirectMemorySize=96M \
-XX:CompressedClassSpaceSize=256M \服務器
一、用jmap,jmap 查看heap內存使用狀況框架
jmap -heap pid
能夠查看到MetaspaceSize,CompressedClassSpaceSize,MaxMetaSize
jmap和jdk版本有關係,有些jdk版本會查看不到內存信息,可使用jstat來查看統計信息ide
二、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 線程棧
NMT能夠獲得線程棧大小,排除棧空間影響。
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
環境:基於B\S的點子考試系統,爲了發現客戶端能實時地從服務端接收考試數據,系統使用了逆向AJAX技術(也稱Comet或Server Side Push),選用CometD1.1.1做爲服務端推送框架,服務器是Jetty7.1.4,硬件爲一臺普通PC機,Core i5 CPU,
4G內存,運行32位Windows操做系統。
說明:測試期間發現服務端不定時拋出內存溢出異常,服務器不必定每次都會出現異常,可是假如正式考試時奔潰一次,那估計整場考試都會全亂套,網站管理員嘗試過把堆開到最大,32位系統最多到1.6GB基本沒法再加大了,並且開大量也基本沒效果,拋出
內存溢出異常好像更加繁瑣了。加入-XX:+HeapDumpOnOutOfMemoryError,竟然也沒有任何反應,拋出內存溢出異常時什麼文件都沒產生。無奈之下只好掛着jstat使勁盯屏幕,發現GC並不頻繁,Eden區,Survivor區,老年代及擁擠代內存所有
表示"情緒穩定,壓力不大",可是照樣不停的拋出內存溢出異常,管理員鴨梨很大。最後,在內存溢出後從系統日誌中找到異常堆棧。
分析:你們都知道操做系統對每一個進程能管理的內存是有限的,這臺服務器使用的32位Windows平臺的限制是2GB,其中給了Java堆1.6GB,而Direct Memory 並不算在1.6GB的堆以內,所以它只能在剩餘的0.4GB空間分出一部分。在此應用中致使內
存溢出的關鍵是:垃圾收集進行時,虛擬機雖然會對Direct Memory進行回收,可是Direct Memory 卻不能像新生代和老年代那樣,發現空間不足了就通知收集器進行垃圾回收,他只能等到拋出內存溢出異常時,先catch掉,再在catch塊裏面「大喊」
「System.gc」.要是虛擬機仍是不聽(如:打開了-XX:+DisableExplicitGC開關),那就只能眼睜睜地看着堆中還有許多空閒內存,本身卻不得不拋出內存異常了。而本案例中使用的Comet1.1.1框架,正好有大量的NIO操做須要用到Direct Memory。
總結:從實踐經驗來看,除了java堆和永久代以外,咱們注意到下面這些區域也會佔用較多的內存,這裏全部的內存總和會受到操做系統進程最大內存的限制:
1.Direct Memory:能夠經過-XX:MaxDirectMemorySize調整大小,內存不足時拋出OutOfMemoryError或OutOfMemoryError:Direct buffer memory。
2.線程堆棧:可經過-Xss調整大小內存不足時拋出StackoverflowErroe(縱向沒法分配,即沒法分配新的棧幀)或OutOfMemoryError:unable to create new native thread(橫向沒法分配,即沒法創建新的線程)。
3.Socket緩存區:每一個Socket鏈接都Receive和Send兩個緩存區,分別佔大約37KB和25KB的內存,鏈接多的話這塊內存佔用也比較可觀。若是沒法分配,則可能會拋出IOException:Too many open files異常。
4.JNI代碼:若是代碼中使用JNI調用本地庫,那麼本地庫使用內存也不在堆中
5.虛擬機和GC:虛擬機和GC的代碼執行也要消耗必定的內存。