JVM 參數(shù):跟蹤垃圾回收
1. 前言
本節(jié)內(nèi)容主要是學(xué)習(xí) JVM 跟蹤垃圾回收的常用參數(shù)配置,這是工作中跟蹤垃圾回收情況時(shí) JVM 中最常用的參數(shù)配置,需要重點(diǎn)對本節(jié)內(nèi)容進(jìn)行學(xué)習(xí)。本節(jié)主要知識點(diǎn)如下:
- 掌握 IntelliJ IDEA 如何配置 JVM 參數(shù),這是我們學(xué)習(xí) JVM 參數(shù)配置的前提。對于有部分同學(xué)使用 Eclipse 作為開發(fā)工具的,可以自行搜索配置方式,此處只針對目前使用廣泛的 IntelliJ IDEA 工具進(jìn)行介紹;
- 理解并掌握跟蹤垃圾回收的參數(shù) -XX:+PrintGC,為本節(jié)重點(diǎn)內(nèi)容;
- 理解并掌握跟蹤垃圾回收的參數(shù) -XX:+PrintGCDetails,為本節(jié)重點(diǎn)內(nèi)容;
- 理解并掌握跟蹤垃圾回收的參數(shù) -XX:+PrintHeapAtGC,為本節(jié)重點(diǎn)內(nèi)容;
- 理解并掌握跟蹤垃圾回收的參數(shù) -XX:+PrintGCTimeStamps,為本節(jié)重點(diǎn)內(nèi)容。
JVM 跟蹤垃圾回收的常用參數(shù)配置是使用 JVM 所必須的知識點(diǎn),通篇皆為重點(diǎn)掌握內(nèi)容,需要在理解的基礎(chǔ)上并掌握參數(shù)的使用方法。
2. IntelliJ IDEA 配置 JVM參數(shù)
通過開發(fā)工具 IntelliJ IDEA 配置 JVM參數(shù),需要打開 “Run->Edit Configurations” 菜單,然后在 VM Options 中添加相應(yīng)的 JVM 參數(shù)。
如上圖為添加 JVM 參數(shù) -XX:+PrintGC 的圖片說明示例,掌握添加參數(shù)的方式,是學(xué)習(xí)具體參數(shù)配置的前提。
3. 示例代碼準(zhǔn)備
為了能夠更好的體會,垃圾回收參數(shù)的執(zhí)行效果,我們需要準(zhǔn)備一段簡易的代碼,供我們執(zhí)行使用,并在代碼中手動執(zhí)行垃圾回收操作,觸發(fā)垃圾回收機(jī)制,使我們的參數(shù)能夠追蹤垃圾回收的動作,并打印相應(yīng)的日志。
實(shí)例:準(zhǔn)備測試代碼,創(chuàng)建一個(gè) String 類型的 ArrayList,并在 list 中添加三個(gè)元素,分別是 “Hello”,“World”,“?。?!”。然后直接手動執(zhí)行垃圾回收操作。
public class PrintGCParamsDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("!!!");
System.gc(); //手動執(zhí)行 gc 垃圾回收
}
}
Tips: 之所以要手動執(zhí)行 gc 垃圾回收,是因?yàn)?JVM 自動的執(zhí)行垃圾回收是需要一定的條件的,簡單的 main 函數(shù)是不能夠達(dá)到觸發(fā)垃圾回收的臨界值的。所以這里手動進(jìn)行 gc 方法的調(diào)用,是為了展示我們的參數(shù)鎖帶來的作用。
4. -XX:+PrintGC 參數(shù)
參數(shù)作用:-XX:+PrintGC 參數(shù)是垃圾回收跟蹤中十分常用的參數(shù)。使用這個(gè)參數(shù)啟動 Java 虛擬機(jī)后,只要遇到 GC,就會打印日志。
為了更好的理解并掌握 -XX:+PrintGC 參數(shù),我們通過如下步驟進(jìn)行操作。
- 步驟 1:在 VM Options 中配置參數(shù) -XX:+PrintGC 并保存;
- 步驟 2:運(yùn)行示例代碼,觀察執(zhí)行結(jié)果。
結(jié)果驗(yàn)證:
[GC (System.gc()) 3933K->792K(251392K), 0.0054898 secs]
[Full GC (System.gc()) 792K->730K(251392K), 0.0290579 secs]
結(jié)果分析:由于這是第一次接觸 JVM 打印日志,我們按照字段逐一進(jìn)行分析。
- GC 與 Full GC:代表了垃圾回收的類型,后續(xù)會有詳細(xì)的講解,這里了解日志意義即可;
- System.gc():代表了引發(fā)方式,是通過調(diào)用 gc 方法進(jìn)行的垃圾回收;
- 3933K->792K(251392K):代表了之前使用了 3933k 的空間,回收之后使用 792k 空間,言外之意這次垃圾回收節(jié)省了 3933k - 792k = 3141k 的容量。251392K 代表總?cè)萘浚?/li>
- 792K->730K(251392K):分析同上;
- 0.0054898 secs:代表了垃圾回收的執(zhí)行時(shí)間,以秒為單位。
那么我們通過上邊的結(jié)果分析,可以非常順利的解讀這兩行日志。
5. -XX:+PrintGCDetails 參數(shù)
參數(shù)作用:-XX:+PrintGCDetails 參數(shù)是垃圾回收跟蹤中十分常用的參數(shù),而且日志更加詳細(xì)。獲取比 -XX:+PrintGC 參數(shù)更詳細(xì)的 GC 信息。
為了更好的理解并掌握 -XX:+PrintGCDetails 參數(shù),我們通過如下步驟進(jìn)行操作。
- 步驟 1:在 VM Options 中配置參數(shù) -XX:+PrintGCDetails 并保存;
- 步驟 2:運(yùn)行示例代碼,觀察執(zhí)行結(jié)果。
結(jié)果驗(yàn)證:
[GC (System.gc()) [PSYoungGen: 3933K->792K(76288K)] 3933K->800K(251392K), 0.0034601 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 792K->0K(76288K)] [ParOldGen: 8K->730K(175104K)] 800K->730K(251392K), [Metaspace: 3435K->3435K(1056768K)], 0.0217628 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
結(jié)果分析: 這里只做新增部分的解釋。
- PSYoungGen:代表了「年輕代」的回收,在這里只需要了解即可,因?yàn)楹罄m(xù)講解 JVM 堆內(nèi)存以及垃圾回收原理時(shí)才會涉及到年輕代;
- ParOldGen:「老年代」這里只需要了解即可,因?yàn)楹罄m(xù)講解 JVM 堆內(nèi)存以及垃圾回收原理時(shí)才會涉及到老年代;
- Metaspace:「元空間」,JDK 的低版本也稱之為永久代,依然,此處了解即可。
我們看到 -XX:+PrintGCDetails 參數(shù)打印了更加詳細(xì)的日志內(nèi)容,把空間清理的部分也表達(dá)的更加詳細(xì)了。
6. -XX:+PrintHeapAtGC 參數(shù)
參數(shù)作用:-XX:+PrintHeapAtGC 參數(shù)是垃圾回收跟蹤中,對堆空間進(jìn)行跟蹤時(shí)十分常用的參數(shù),可以在每次 GC 前后分別打印堆的信息。注意,是 GC 前后均打印,打印兩次。
為了更好的理解并掌握 -XX:+PrintHeapAtGC 參數(shù),我們通過如下步驟進(jìn)行操作。
- 步驟 1:在 VM Options 中配置參數(shù) -XX:+PrintHeapAtGC 并保存;
- 步驟 2:運(yùn)行示例代碼,觀察執(zhí)行結(jié)果。
結(jié)果驗(yàn)證:
{Heap before GC invocations=1 (full 0):
PSYoungGen total 76288K, used 3933K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
eden space 65536K, 6% used [0x000000076b400000,0x000000076b7d7480,0x000000076f400000)
from space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
to space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000)
ParOldGen total 175104K, used 0K [0x00000006c1c00000, 0x00000006cc700000, 0x000000076b400000)
object space 175104K, 0% used [0x00000006c1c00000,0x00000006c1c00000,0x00000006cc700000)
Metaspace used 3420K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
Heap after GC invocations=1 (full 0):
PSYoungGen total 76288K, used 792K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
eden space 65536K, 0% used [0x000000076b400000,0x000000076b400000,0x000000076f400000)
from space 10752K, 7% used [0x000000076f400000,0x000000076f4c6030,0x000000076fe80000)
to space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
ParOldGen total 175104K, used 0K [0x00000006c1c00000, 0x00000006cc700000, 0x000000076b400000)
object space 175104K, 0% used [0x00000006c1c00000,0x00000006c1c00000,0x00000006cc700000)
Metaspace used 3420K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
}
{Heap before GC invocations=2 (full 1):
PSYoungGen total 76288K, used 792K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
eden space 65536K, 0% used [0x000000076b400000,0x000000076b400000,0x000000076f400000)
from space 10752K, 7% used [0x000000076f400000,0x000000076f4c6030,0x000000076fe80000)
to space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
ParOldGen total 175104K, used 0K [0x00000006c1c00000, 0x00000006cc700000, 0x000000076b400000)
object space 175104K, 0% used [0x00000006c1c00000,0x00000006c1c00000,0x00000006cc700000)
Metaspace used 3420K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
Heap after GC invocations=2 (full 1):
PSYoungGen total 76288K, used 0K [0x000000076b400000, 0x0000000770900000, 0x00000007c0000000)
eden space 65536K, 0% used [0x000000076b400000,0x000000076b400000,0x000000076f400000)
from space 10752K, 0% used [0x000000076f400000,0x000000076f400000,0x000000076fe80000)
to space 10752K, 0% used [0x000000076fe80000,0x000000076fe80000,0x0000000770900000)
ParOldGen total 175104K, used 705K [0x00000006c1c00000, 0x00000006cc700000, 0x000000076b400000)
object space 175104K, 0% used [0x00000006c1c00000,0x00000006c1cb07a0,0x00000006cc700000)
Metaspace used 3420K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 371K, capacity 388K, committed 512K, reserved 1048576K
}
結(jié)果分析: 由于這是對「堆空間」的日志打印,在學(xué)習(xí)完 JVM 堆空間之前,了解即可。對于堆空間的參數(shù)跟蹤,這里進(jìn)行了更加細(xì)致的打印。從結(jié)果來看,在 GC 前后,打印了兩次堆空間信息,并且將 PSYoungGen 以及 ParOldGen 進(jìn)行了更加詳細(xì)的日志打印。
后續(xù)學(xué)習(xí)完 JVM堆空間之后,回望這部分知識,會非常的簡單,此處也必須要先了解,為后續(xù)對堆的學(xué)習(xí)打下良好的基礎(chǔ)。
7. -XX:+PrintGCTimeStamps 參數(shù)
參數(shù)作用:會在每次 GC 發(fā)生時(shí),額外輸出 GC 發(fā)生的時(shí)間,該輸出時(shí)間為虛擬機(jī)啟動后的時(shí)間偏移量。需要與 -XX:+PrintGC 或 -XX:+PrintGCDetails 配合使用,單獨(dú)使用 -XX:+PrintGCTimeStamps 參數(shù)是沒有效果的。
為了更好的理解并掌握 -XX:+PrintGCTimeStamps 參數(shù),我們通過如下步驟進(jìn)行操作。
- 步驟 1:在 VM Options 中配置參數(shù) -XX:+PrintGC -XX:+PrintGCTimeStamps 并保存;
- 步驟 2:運(yùn)行示例代碼,觀察執(zhí)行結(jié)果。
結(jié)果驗(yàn)證:
0.247: [GC (System.gc()) 3933K->760K(251392K), 0.0114098 secs]
0.259: [Full GC (System.gc()) 760K->685K(251392K), 0.0079185 secs]
結(jié)果分析:我們看到了,與 -XX:+PrintGC 參數(shù)打印的結(jié)果,唯一的區(qū)別就是日志開頭的 0.247 與 0.259。此處 0.247 與 0.259 表示, JVM開始運(yùn)行 0.247 秒后發(fā)生了 GC,開始運(yùn)行 0.259 秒后,發(fā)生了 Full GC。
8. 小結(jié)
本小節(jié)的重點(diǎn)內(nèi)容,即我們所講述的四個(gè)常見的跟蹤垃圾回收的參數(shù),學(xué)習(xí)者,需要對這四個(gè)常用參數(shù)的意義,以及使用方式進(jìn)行掌握。由于日志輸出中部分內(nèi)容,涉及到的知識點(diǎn)還沒有講到,但是本節(jié)對于這些內(nèi)容的初步接觸,能夠有利于學(xué)習(xí)者,在后續(xù)的學(xué)習(xí)中提升學(xué)習(xí)的效率,以及理解效率。