常見參數
java啓動參數
參數 | 說明 |
---|---|
- | 所有jvm實現都必須實現這些參數的功能,向後兼容 |
-X | 默認jvm實現這些參數的功能,不保證所有jvm實現都滿足,不保證向後兼容 |
-XX | 各個jvm實現有所不同,可能會隨時取消 |
輸出jvm的信息參數
參數 | 說明 |
---|---|
-verbose:gc | 輸出每次GC的相關信息 |
-XX:+PrintGCDetails | 獲取的信息比上面更多 |
更多信息
參數 | 說明 |
---|---|
-XX:PrintGCTimeStamps | 顯示jvm啓動到執行GC時流逝的時間,單位是秒 |
-XX:PrintDateTimeStamps | 顯示執行GC時的本地時間(Java 6 update 4纔開始支持) |
-Xloggc:/Users/cc/Desktop/log.txt | gc信息重定向到文件 |
解讀log信息
CommandLine flags: -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
0.465: [GC (System.gc()) [PSYoungGen: 5341K->851K(38400K)] 5341K->859K(125952K), 0.0020406 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.467: [Full GC (System.gc()) [PSYoungGen: 851K->0K(38400K)] [ParOldGen: 8K->778K(87552K)] 859K->778K(125952K), [Metaspace: 3653K->3653K(1056768K)], 0.0064182 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 38400K, used 1553K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 4% used [0x0000000795580000,0x00000007957045f8,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
to space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGen total 87552K, used 778K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x00000007400c2ab8,0x0000000745580000)
Metaspace used 3775K, capacity 4888K, committed 5120K, reserved 1056768K
class space used 419K, capacity 456K, committed 512K, reserved 1048576K
System.out.println(Runtime.getRuntime().maxMemory()); System.out.println(Runtime.getRuntime().freeMemory()); System.out.println(Runtime.getRuntime().totalMemory());
JVM內存結構
JVM的內存由棧寄存器和堆構成,堆裏面有新生代、老年代和持久代。
Young(年輕代)
分爲Eden(伊甸)區,兩個survivor(存活)區。大部分對象(剛new出的對象)在Eden區,當Eden區滿時,還存貨的對象被複制到survivor區中的一個,當這個survivor區滿時,此區的存活對象將被複制到另外一個survivor區,當這個survivor區滿時,從第一個survivor區複製過來的並且此時還存活的對象,被複制到“老年代”。survivor總有一個是空的。
Tenured(老年代)
老年代存放從年輕代存活的對象,一般來說老年代存放的都是生命週期較長的對象
Perm(持久代)
用於存放靜態文件,如java類,方法。持久代對垃圾回收沒有顯著影響.final修飾的常量,classLoader加載的信息。
GC的兩種類型
ScavengeGC(Minor GC) | Full GC |
---|---|
一般情況下,當新對象生成並且在Eden申請空間失敗時,觸發scavengeGC,堆Eden區域進行GC,清楚非存活對象,並將尚且存活的對象移動到survivor區,然後整理survivor的兩個區 | 對整個堆進行真理,包括young tenured和perm。 |
觸發:Eden區滿 | 觸發full gc的三種原因:tenured被寫滿;perm被寫滿;System.gc()被顯式調用 |
新生代發生的垃圾回收操作,因爲java對象大多具有朝生夕滅的特性,所以minorGC非常頻繁,一般回收速度也比較快,通常在百毫秒級 | 老年代GC(FullGC/MajorGC)發生在老年代的GC,出現了MajorGC經常會伴隨至少一次的MinorGC(非絕對,在parallelscavenge收集器的手機策略裏就有直接進行majorGC的策略選擇過程)。majorGC的速度一般會比MinorGC慢10倍以上,1.4G的Old Gen進行一次回收通常需要20-40秒 |
首次YGC:對Eden區進行垃圾回收,回收後Eden區中依然存活的對象被移入S0 第二次YGC:將s0中的對象複製到s1,並對Eden區和s1進行垃圾回收,回收後Eden區依然存活的對象被移入s1,並將s0中所有的對象清楚,以此類推,在S0/S1中存活次數超過N次(默認15次)的對象移入OldGen,如果S0/S1空間不足,則直接移入Old Gen | 對young gen,old gen,perm gen進行一次完整的垃圾回收,old gen不在被引用的對象直接銷燬,young gen的回收算法同youngGC,perm GEM回收方式爲,如果堆中不存在某個類的任何勢力,且該類的Class對象沒有在任何地方被引用,則該類被回收 |
虛擬機給每個對象定義了一個對象年齡(Age)計數器,如果對象在Eden出生並經過第一次MinorGC後仍然存活,並且能被survivor容納的話,將被移動到survivor空間中,並將對象年齡設爲1.對象在survivor區中每熬過一次MinorGC,年齡就增加一歲,當它的年齡增加到一定程度(默認爲15歲)時,就會被晉升到老年代中。對象晉升老年代的年齡閾值 通過-XX:MaxTenuringThreshhold來設置
jstat -gcutil <pid> <timediff>
用jstat查看jvm內存使用情況
s0 | s1 | E | O | P | YGC | YGCT | FGC | FGCT | GCT |
---|---|---|---|---|---|---|---|---|---|
S0區佔用的空間比 | s1 | Eden區 | Old區 | Perm區 | YGC的次數 | YGCtime從程序啓動到採用ygc所有的時間/s | FGC次數 | FGC時間/s | 用於垃圾回收的總時間/s |
xiejiangqiongdeMacBook-Pro:~ cc$ jstat -gcutil 5061 1000
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.capacity substituted NaN
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.used substituted NaN
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.capacity substituted NaN
S0 S1 E O P YGC YGCT FGC FGCT GCT
75.66 0.00 0.00 99.76 � 18 2.212 5 2.398 4.610
73.66 0.00 20.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 44.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 64.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 84.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 100.00 65.58 � 18 2.212 5 4.433 6.645
0.00 100.00 8.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 32.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 50.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 68.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 86.00 68.23 � 19 2.613 5 4.433 7.046
2.72 100.00 100.00 81.55 � 20 2.613 5 4.433 7.046
51.81 0.00 0.00 88.70 � 20 3.010 6 4.433 7.443
5.87 0.00 2.00 69.16 � 20 3.010 6 6.121 9.130
5.87 0.00 30.00 69.16 � 20 3.010 6 6.121 9.130
5.87 0.00 54.00 69.16 � 20 3.010 6 6.121 9.130
用ps -ef | grep java
查看待檢測進程的id
uid | pid | ppid | c | stime | tty | cmd |
---|---|---|---|---|---|---|
用戶ID | 進程ID | 父進程ID | 開始時間 | 登錄方式 | 命令 |
從我的畢設中大量的FullGC看內存
內存泄露時會發生什麼
- 某些對象會佔用大量的JVM內存,且長時間無法被回收掉。這些長時間無法被回收的對象通常都會在Old Gen中
- 由於Old Gen中存在大量無法被回收的對象,每次FullGC只能釋放出極少的Old Gen空間,回收處的這少部分Old Gen空間又會很快被佔滿,這就會導致JVM在頻繁地進行FullGC
- FullGC很慢,而JVM在做GC時會stop-the-world,在GC時終止JVM的一切工作。所以假設在內存泄露發生時,JVM被迫每40秒做一次FullFC,每次FullGC需要30秒,這就代表JVM只有1/4的時間在正常工作,此時的性能一定是非常慢的
- 而隨着泄露對象的不斷增加,OldGen的可用空間會越來越少,最終JVM會回收不出足夠的可用內容以支撐程序的運行,從而導致服務的徹底不可用
通過jstat觀察Old Gen內存佔用的增長速度,以及GC的頻次
- 如果jstat命令輸出的信息表示JVM正在頻繁進行FullGC,那麼基本而已肯定性能故障的原因是內存泄露
[Full GC (Ergonomics) 3344336K->3068858K(3749376K), 3.7187515 secs]
[Full GC (Ergonomics) 3344336K->3091406K(3749376K), 3.2715931 secs]
[Full GC (Ergonomics) 3344336K->3112195K(3749376K), 3.9227456 secs]
[Full GC (Ergonomics) 3344336K->3139728K(3749376K), 3.5998555 secs]
參考博客
日誌信息解讀
IDEA JVM運行參數
JVM參數原理和性能調優
jvm調優總結+jstat分析 很好的總結
java gc的工作原理 minor gc full gc的原理
關於tomcat上的性能