4、JVM垃圾回收机制、新生代的GC、GC(Minor GC、FullGC)、GC日志、JVM参数选项、元空间(笔记)
4.JVM垃圾回收機制
4.1.新生代的GC
4.1.1.串行GC(SerialGC)
4.1.2.并行回收GC(Parallel Scavenge)
4.1.3.并行GC(ParNew)
4.2.GC(Minor GC、FullGC)
4.2.1.Minor GC
4.2.2.FullGC
4.3.GC日志
4.JVM垃圾回收機制
JVM分別對新生代和老年代采用不同的垃圾回收機制。
4.1.新生代的GC
新生代通常存活時間較短,因此基于復制算法來進行回收,所謂復制算法就是掃描出存活的對象,并復制到一塊新的完全未使用的空間中,對應于新生代,就是在Eden和其中一個Survivor,復制到另一個之間Survivor空間中,然后清理掉原來就是在Eden和其中一個Survivor中的對象。新生代采用空閑指針的方式來控制GC觸發,指針保持最后一個分配的對象在新生代區間的位置,當有新的對象要分配內存時,用于檢查空間是否足夠,不夠就觸發GC。當連續分配對象時,對象會逐漸從eden到 survivor,最后到老年代。
用java visualVM來查看,能明顯觀察到新生代滿了后,會把對象轉移到舊生代,然后清空繼續裝在,當舊生代也滿了后,就會報OutOfMemory的異常。
在執行機制上JVM提供了串行GC(SerialGC)、并行回收GC(ParallelScavenge)和并行GC(ParNew)。
4.1.1.串行GC(SerialGC)
在整個掃描和復制過程采用單線程的方式來進行,適用于單CPU、新生代空間較小及對暫停時間要求不是非常高的應用上,是client級別默認的GC方式,可以通過-XX:+UseSerialGC來強制指定。
4.1.2.并行回收GC(Parallel Scavenge)
在整個掃描和復制過程采用多線程的方式來進行,適用于多CPU、對暫停時間要求較短的應用上,是server級別默認采用的GC方式,可用-XX:+UseParallelGC來強制指定,用-XX:ParallelGCThreads=4來指定線程數。
4.1.3.并行GC(ParNew)
與舊生代的并發GC配合使用。
舊生代的GC:
舊生代與新生代不同,對象存活的時間比較長,比較穩定,因此采用標記(Mark)算法來進行回收,所謂標記就是掃描出存活的對象,然后再進行回收未被標記的對象,回收后對用空出的空間要么進行合并,要么標記出來便于下次進行分配,總之就是要減少內存碎片帶來的效率損耗。在執行機制上JVM提供了串行 GC(SerialMSC)、并行GC(parallelMSC)和并發GC(CMS),具體算法細節還有待進一步深入研究。
4.2.GC(Minor GC、FullGC)
GC分為兩種:Minor GC、FullGC(或稱為Major GC)。
4.2.1.Minor GC
從年輕代空間(包括 Eden 和 Survivor 區域)回收內存被稱為Minor GC。
當發生Minor GC事件的時候,有一些有趣的地方需要注意到:
?當 JVM 無法為一個新的對象分配空間時會觸發 Minor GC,比如當 Eden 區滿了。所以分配率越高,越頻繁執行 Minor GC。
?內存池被填滿的時候,其中的內容全部會被復制,指針會從0開始跟蹤空閑內存。Eden 和 Survivor 區進行了標記和復制操作,取代了經典的標記、掃描、壓縮、清理操作。所以 Eden 和 Survivor 區不存在內存碎片。寫指針總是停留在所使用內存池的頂部。
?執行 Minor GC 操作時,不會影響到永久代。從永久代到年輕代的引用被當成 GC roots,從年輕代到永久代的引用在標記階段被直接忽略掉。
?質疑常規的認知,所有的 Minor GC都會觸發”stop-the-world”,停止應用程序的線程。對于大部分應用程序,停頓導致的延遲都是可以忽略不計的。其中的真相就是,大部分 Eden區中的對象都能被認為是垃圾,永遠也不會被復制到Survivor區或者老年代空間。如果正好相反,Eden 區大部分新生對象不符合 GC 條件,Minor GC 執行時暫停的時間將會長很多。
每次Minor GC會清理年輕代的內存。
Minor GC是發生在新生代中的垃圾收集動作,所采用的復制算法。
當一個對象被判定為”死亡”的時候,GC就有責任來回收掉這部分對象的內存空間。新生代是GC收集垃圾的頻繁區域。
當對象在Eden (包括一個 Survivor 區域,這里假設是 from 區域)出生后,在經過一次Minor GC后,如果對象還存活,并且能夠被另外一塊Survivor區域所容納(上面已經假設為 from 區域,這里應為to 區域,即to區域有足夠的內存空間來存儲Eden和from區域中存活的對象),則使用復制算法將這些仍然還存活的對象復制到另外一塊Survivor區域(即to區域)中,然后清理所使用過的Eden以及Survivor區域(即from區域),并且將這些對象的年齡設置為1,以后對象在Survivor 區每熬過一次 Minor GC,就將對象的年齡+ 1,當對象的年齡達到某個值時 ( 默認是 15 歲,可以通過參數 -XX:MaxTenuringThreshold來設定),這些對象就會成為老年代。
但這也不是一定的,對于一些較大的對象(即需要分配一塊較大的連續內存空間)則是直接進入到老年代。
4.2.2.FullGC
Full GC是發生在老年代的垃圾收集動作,所采用的是標記-清除算法。
現實的生活中,老年代的人通常會比新生代的人”早死”。堆內存中的老年代(Old)不同于這個老年代里面的對象幾乎個個都是在Survivor區域中熬過來的,它們是不會那么容易就”死掉”了的。
因此,Full GC發生的次數不會有Minor GC那么頻繁,并且做一次Full GC要比進行一次Minor GC的時間更長。
另外,標記-清除算法收集垃圾的時候會產生許多的內存碎片(即不連續的內存空間),此后需要為較大的對象分配內存空間時,若無法找到足夠的連續的內存空間,就會提前觸發一次GC的收集動作。
4.3.GC日志
案例
package com.toto.jvm;public class Demo {public static void main(String[] args) {Object obj = new Object();System.gc();System.out.println();obj = new Object();obj = new Object();System.gc();System.out.println();} }設置VM arguments:-verbose:gc -XX:+PrintGCDetails
Run之后,輸出結果:
System.gc()可以觸發Full GC
[GC (System.gc()) [PSYoungGen: 5201K->752K(151552K)] 5201K->760K(498688K), 0.0012719 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 752K->0K(151552K)] [ParOldGen: 8K->536K(347136K)] 760K->536K(498688K), [Metaspace: 2587K->2587K(1056768K)], 0.0088355 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [GC (System.gc()) [PSYoungGen: 2600K->96K(151552K)] 3137K->632K(498688K), 0.0005806 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 96K->0K(151552K)] [ParOldGen: 536K->535K(347136K)] 632K->535K(498688K), [Metaspace: 2588K->2588K(1056768K)], 0.0064823 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] HeapPSYoungGen total 151552K, used 2601K [0x0000000716d00000, 0x0000000721600000, 0x00000007c0000000)eden space 130048K, 2% used [0x0000000716d00000,0x0000000716f8a578,0x000000071ec00000)from space 21504K, 0% used [0x0000000720100000,0x0000000720100000,0x0000000721600000)to space 21504K, 0% used [0x000000071ec00000,0x000000071ec00000,0x0000000720100000)ParOldGen total 347136K, used 535K [0x00000005c4600000, 0x00000005d9900000, 0x0000000716d00000)object space 347136K, 0% used [0x00000005c4600000,0x00000005c4685f60,0x00000005d9900000)Metaspace used 2594K, capacity 4486K, committed 4864K, reserved 1056768Kclass space used 288K, capacity 386K, committed 512K, reserved 1048576K設置JVM參數為-verbose:gc -XX:+PrintGCDetails,使得控制臺能夠顯示GC相關的日志信息,執行上面代碼,下面是其中一次執行的結果。
jstate -gc -t 4235 1s5.JVM參數選項
下面只列舉其中的幾個常用和容易掌握的配置選項
| -Xms | 初始堆大小。如:-Xms256m |
| -Xmx | 最大堆大小。如:-Xmx512m |
| -Xmn | 新生代大小。通常為Xmx的1/3 或1/4。新生代 = Eden + 2個Survivor空間。實際可用空間為 = Eden + 1 個Survivor,即90% |
| -Xss | JDK1.5+每個線程堆棧大小為1M,一般來說如果棧不是很深的話,1M是絕對夠用了的。 |
| -XX:NewRatio | 新生代與老年代的比例,如–XX:NewRatio=2,則新生代占整個堆空間的1/3,老年代占2/3 |
| -XX:SurvivorRatio | 新生代中Eden與Survivor 的比值。默認值為8。即 Eden占新生代空間的8/10,另外兩個 Survivor 各占 1/10 |
| -XX:PermSize | 永久代(方法區)的初始大小 |
| -XX:MaxPermSize | 永久代(方法區)的最大值 |
| -XX:+PrintGCDetails | 打印GC信息 |
| -XX:+HeapDumpOnOutOfMemoryError | 讓虛擬機在發生內存溢出時Dump出當前的內存堆轉儲快照,以便分析用。 |
-XX:Newratio: 設置Old和Yong的比例,比如值為2,則Old Generation是 Yong Generation的2倍,即Yong Generation占據內存的1/3
-XX:Newsize : 設置Yong Generation的初始值大小
-XX:Maxnewsize:設置Yong Generation的最大值大小
-XX:Surviorratio : 設置Eden和一個Suivior的比例,比如值為5,即Eden是To(S2)的比例是5,(From和To是一樣大的),此時Eden占據Yong Generation的5/7
一般情況下,不允許-XX:Newratio值小于1,即Old要比Yong大。
6.元空間
元空間的本質和永久代類似,都是對JVM規范中方法區的實現。不過元空間與永久代之間最大的區別在于:元空間并不在虛擬機中,而是使用本地內存。因此,默認情況下,元空間的大小受本地內存限制。
總結
以上是生活随笔為你收集整理的4、JVM垃圾回收机制、新生代的GC、GC(Minor GC、FullGC)、GC日志、JVM参数选项、元空间(笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创投板块有哪些上市公司 一笔投资可能就改
- 下一篇: 安逸花云闪付怎么提现