由於在Linux環境,用jdk自帶的jmap工具(Linux/Unix環境特有的),能夠對進程中的內存對象監視,而後就運行命令java
jmap -histo [pid],找內存中的對象數目變化。linux
watch "jmap -histo 7220| grep u9"
瀏覽器
查看有u9字段的對象數目和大小tomcat
查看服務器
jvm中對象內存佔用狀況(jmap -histo pid | head -n8, 由於內容太多, 所以須要head一下)併發
導出整個JVM中的內存信息運維
經過以上方法能查看到JVM中對象內存的佔用狀況,但不少時候還要知道這個對象究竟是誰建立的。例如上面顯示出來的[C,只知道它佔用了那麼多的空間,但不知道是什麼對象建立出的[C,因而jmap提供了導出整個jvm中的內存信息的支持。基於一些jvm內存的分析工具,例如sun JDK 6中的jhat、Eclipse Memory Analyzer,能夠分析jvm中內存的詳細信息,例如[C是哪些對象建立的。eclipse
----------------------------------------------------jvm
執行以下命令便可導出整個jvm中的內存信息:
-------------------------------------------------------
jmap -heap [pid] 在linux上執行改命令,就可查看整個JVM中各個代的內存情況
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1610612736 (1536.0MB)
NewSize = 524288000 (500.0MB)
MaxNewSize = 524288000 (500.0MB)
OldSize = 4194304 (4.0MB)
NewRatio = 8
SurvivorRatio = 8
PermSize = 100663296 (96.0MB)
MaxPermSize = 268435456 (256.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 430702592 (410.75MB)
used = 324439936 (309.4100341796875MB)
free = 106262656 (101.3399658203125MB)
75.32806675098904% used
From Space:
capacity = 46333952 (44.1875MB)
used = 13016424 (12.413429260253906MB)
free = 33317528 (31.774070739746094MB)
28.092626331550566% used
To Space:
capacity = 46792704 (44.625MB)
used = 0 (0.0MB)
free = 46792704 (44.625MB)
0.0% used
PS Old Generation
capacity = 1086324736 (1036.0MB)
used = 945707880 (901.8973159790039MB)
free = 140616856 (134.1026840209961MB)
87.05572548059884% used
PS Perm Generation
capacity = 100663296 (96.0MB)
used = 46349592 (44.202415466308594MB)
free = 54313704 (51.797584533691406MB)
46.044182777404785% used
若是PS Old Generation或者PS Perm Generation被填滿,就會致使fullGC,進而致使CPU佔用率大幅度提升
--------------------------------
併發回收 CMS收集器 UseConcMarkSweepGC
適用狀況:「對響應時間有高要求」,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發環境。
並行回收 UseParallelGC
--適用狀況:「對吞吐量有高要求」,多CPU、對應用響應時間無要求的中、大型應用。舉例:後臺處理、科學計算。
--缺點:垃圾收集過程當中應用響應時間可能加長
最大垃圾回收暫停:指定垃圾回收時的最長暫停時間,經過-XX:MaxGCPauseMillis=<N>指定。<N>爲毫秒.若是指定了此值的話,堆大小和垃圾回收相關參數會進行調整以達到指定值。設定此值可能會減小應用的吞吐量。
吞吐量:吞吐量爲垃圾回收時間與非垃圾回收時間的比值,經過-XX:GCTimeRatio=<N>來設定,公式爲1/(1+N)。例如,-XX:GCTimeRatio=19時,表示5%的時間用於垃圾回收。默認狀況爲99,即1%的時間用於垃圾回收。
引用一個網友實例:
猜測:在HeapSpace逼近臨界值的時候,分配小塊內存(譬如建立一個對象,若是是分配大塊內存,實際上JVM直接就報OutOfMemory了),JVM發現內存不足,會嘗試去FullGC出空閒內存,每次還真能擠出一點點,但很快又得從新FullGC,咱們知道,實際上FullGC是很是消耗CPU的操做。但爲啥不報OutOfMemory呢?由於每次總可以釋放出一點點內存,所以居然就這麼維持下去了。這裏很是鬱悶,JVM直接報OutOfMemory還好過一點,至少直接知道緣由。
JVM通常啓動參數有一個GCTimeRatio參數,表示目標吞吐量,JVM會自動調整各內存區大小去達到該吞吐量值,若是吞吐量低於某個值,是會自動OutOfMemory,目前該值默認是1,表示GC時間佔總時間不超過1%,但目前來看,要經過這種方式去讓JVM直接報告OutOfMemory而不是持續維持高CPU看起來是不行的。
已經能夠定位到是內存達到臨界值的問題,接下來問題就簡單了,dump出HeapSpace空間,使用Eclipse Memory Analyzer分析一下,緣由一目瞭然,有點訝異,居然是BlackStar的detail工做模式致使的,這裏是由於使用的時候策略沒有調整好,調整detail策略,從新啓動JVM,問題解決,固然這裏BlackStar的detail工做模式的自我保護方式也很差,實際上當發現使用內存過多的時候,應該調整自動放棄。
----------------------------------------------------------------
JStat用於GC分析的參數有:-gc、-gccapacity、-gccause、-gcnew、-gcnewcapacity、-gcold、-gcoldcapacity、-gcpermcapacity、-gcutil。經常使用的爲-gcutil。經過-gcutil可按必定頻率查看jvm中各代的空間的佔用狀況、minor GC的次數、消耗的時間、full GC的次數及消耗的時間的統計,執行jstat -gcutil [pid] [interval],另外能夠指定更新頻率,如-h5 1s:每一秒更新一次,並每隔5條加上header顯示,好比jstat -gcutil -h5 28525 1s,表示每隔一秒更新一次,並每隔5條加上header顯示
可看到相似以下的輸出信息:
S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 74.24 96.73 73.43 46.05 17808 382.335 208 315.197 697.533 45.37 0.00 28.12 74.97 46.05 17809 382.370 208 315.197 697.568
其中S0、S1就是Survivor空間的使用率,E表示Eden空間的使用率,O表示舊生代空間的使用率,P表示持久代的使用率,YGC表示minor GC的執行次數,YGCT表示minor GC執行消耗的時間,FGC表示Full GC的執行次數,FGCT表示Full GC執行消耗的時間,GCT表示Minor GC+Full GC執行消耗的時間。
觀察了一下外網數據,每隔兩分鐘會執行一次minor GC,也就是說Eden空間每隔兩分鐘就會被充滿,而後會填充S0或者S1,填充次序爲輪換執行,也就是此次爲S0,下次必爲S1,
FGC的平均時間爲1S左右,minor GC的平均時間爲16ms,也就是一個晶振時間,平均一天一次FGC,710次minor GC
對TJ06-盛大3區 gameserver採樣
S0:Heap上的 Survivor space 0 段已使用空間的百分比
S1:Heap上的 Survivor space 1 段已使用空間的百分比
E: Heap上的 Eden space 段已使用空間的百分比
O: Heap上的 Old space 段已使用空間的百分比
P: Perm space 已使用空間的百分比
YGC:從程序啓動到採樣時發生Young GC的次數
YGCT:Young GC所用的時間(單位秒)
FGC:從程序啓動到採樣時發生Full GC的次數
FGCT:Full GC所用的時間(單位秒)
GCT:用於垃圾回收的總時間(單位秒)
jstat -gccapacity <jpid>:JVM各區的剩餘狀態
------------------------------------------------------
jps 目前正在運行中的java進程
-----------------------------------------------------
jstack
jstack -l <jpid>:顯示線程阻塞/死鎖狀況
瞭解 Java 進程及其對應的執行線程內部發生的狀況是一種常見的診斷挑戰。例如,當一個應用程序忽然中止進程時,很明顯出現了資源耗盡,可是僅經過查看代碼沒法明確知道何處出現資源耗盡,且爲何會發生。
jstack 是一個能夠返回在應用程序上運行的各類各樣線程的一個完整轉儲的實用程序,您可使用它查明問題。
採用指望進程的 VMID 運行 jstack 會產生一個堆轉儲。就這一點而言,jstack 與在控制檯窗口內按 Ctrl-Break 鍵起一樣的做用,在控制檯窗口中,Java 進程正在運行或調用 VM 內每一個 Thread 對象上的 Thread.getAllStackTraces() 或 Thread.dumpStack()。jstack 調用也轉儲關於在 VM 內運行的非 Java 線程的信息,這些線程做爲 Thread 對象並不老是可用的。
jstack 的 -l 參數提供了一個較長的轉儲,包括關於每一個 Java 線程持有鎖的更多詳細信息,所以發現(和 squash)死鎖或可伸縮性 bug 是極其重要的。
----------------------------------------------------
JVM內存情況查看方法和分析工具
Eclipse Memory Analyzer
Eclipse Memory Analyzer是Eclipse提供的一個用於分析jvm堆dump文件的插件,藉助這個插件可查看對象的內存佔用情況、引用關係、分析內存泄露等。
Eclipse Memory Analyzer(MAT)的網站爲:http://www.eclipse.org/mat/,在eclipse中能夠直接遠程安裝此插件。不過因爲此插件在分析堆dump文件時比較耗內存,所以在分析前最好先將eclipse的jvm的內存設置大一點,MAT分析dump文件後的對象佔用內存及引用關係如圖3.23所示。
相對而言MAT功能比jhat強大不少,分析的速度也快一些,所以,若是要分析jvm堆dumap文件,首選推薦的是MAT。
在進行JVM內存情況分析時,一般要關注的主要有GC的趨勢、內存的具體消耗情況。
GC趨勢對於可圖形界面連到需查看GC情況的機器的狀況而言,VisualVM是經常使用的選擇;對於不能採用圖形界面方式的,輸出GC日誌 及採用jstat命令直接分析是經常使用的選擇。
在查找內存是程序中的什麼對象佔用時,須要分析內存的具體消耗情況,對於有圖形界面可用的狀況,VisualVM是經常使用的選擇;對於不能採用圖形界面方式的,可經過jmap dump生成文件後,再經過MAT進行分析是經常使用的選擇。
參考文獻:
最後附上JVM參數調優的案例,其中批註一下-server的參數使用
.-server
-client
虛擬機服務器模式/客戶機模式,使用server模式能夠提升性能,啓動比client模式慢,長期運行則比client模式快。當該參數不指定時,虛擬機啓動檢測主機是否爲服務器,若是是則以server模式啓動,不然以client模式啓動,J2SE5.0檢測的根據是至少2個CPU和最低2GB內存
今天在用jstat命令的時候,遇到pid not found的問題,然,本身肯定pid輸入是正確存在的,但爲何呢?
原來運維那邊每隔一個月,通常在月底都會去清空一下tmp目錄下的文件,致使/tmp/hsperfdata_${user}/${PID}文件沒了,
user 例如 是admin root等等
pid就是 你當前運行的java的pid了。
順便說下 若是jstat出現 pid not found ,那用jps也看不到這個進程了。
我這邊由於是 這個pid文件被刪除了,因此不能看了。
解決方法是重啓服務就ok了
----------------------------
JVM 參數優化
-server -Xms2g -Xmx2g -XX:PermSize=96m -XX:MaxPermSize=256m -Xmn1024m -verbose:gc
-Xloggc:/home/yahoo/output/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:+DisableExplicitGC
參數 |
說明 |
-server |
服務機模式,不配置默認的是-client,必定要做爲第一個參數,在多個CPU時性能佳 |
-Xms2g -Xmx2g |
堆大小,線上的堆的最大值與最小值必須一致,免得jvm調整堆大小浪費性能。 |
-Xmn1024m |
堆中新生代大小,通常爲堆的一半多些 |
-XX:PermSize=96m -XX:MaxPermSize=256m |
jvm方法區空間大小 |
-Xloggc:/home/yahoo/output/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps |
打GC日誌,這不會給系統帶來啥負擔,建議線上機器都加上,方便調優和OutOfMemory後查錯。 |
-verbose:gc |
將虛擬機的垃圾回收事件信息打印 |
-XX:+UseConcMarkSweepGC |
新生代採用ParNew GC方式,舊生代採用併發GC方式,以減小系統停頓時間爲優先,縮短major收集的時間,此選項在Heap Size 比較大並且Major收集時間較長的狀況下使用更合適。 |
-XX:+DisableExplicitGC |
禁止程序觸發GC |
-Xloggc:gc.log 指定垃圾收集日誌文件
-XX:+UseParNewGC :縮短minor收集的時間
HeapDumpOnOutOfMemoryError
在jvm的 啓動參數中追加 下列信息,能夠在發生 OutOfMemoryError的時候生成 oom.hprof文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:/temp/oom.hprof