爲了解決引用計數法的循環引用問題,Java 使用了可達性算法。html
跟蹤收集器採用的爲集中式的管理方式,全局記錄對象之間的引用狀態,執行時從一些列GC Roots的對象作爲起點,從這些節點向下開始進行搜索全部的引用鏈,當一個對象到GC Roots 沒有任何引用鏈時,則證實此對象是不可用的。java
圖中,對象Object六、Object七、Object8雖然互相引用,但他們的GC Roots是不可到達的,因此它們將會被斷定爲是可回收的對象。ios
哪些對象能夠做爲 GC Roots 的對象:算法
XX 參數緩存
jinfo 舉例,如何查看當前運行程序的配置服務器
1 2 3 4 5 6 7 8 9 10 |
public class HelloGC { public static void main(String[] args) { System.out.println("hello GC..."); try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } } |
咱們可使用 jps -l
命令,查出進程 id網絡
1 2 3 4 5 6 |
1923 org.jetbrains.jps.cmdline.Launcher 1988 sun.tools.jps.Jps 1173 org.jetbrains.kotlin.daemon.KotlinCompileDaemon 32077 com.intellij.idea.Main 1933 com.cuzz.jvm.HelloGC 32382 org.jetbrains.idea.maven.server.RemoteMavenServer |
在使用 jinfo -flag PrintGCDetails 1933
命令查看併發
1 |
-XX:-PrintGCDetails |
能夠看出默認是不打印 GC 收集細節jvm
也但是使用jinfo -flags 1933
查看因此的參數maven
兩個經典參數:-Xms 和 - Xmx(如 -Xms1024m)
查看初始默認值:-XX:+PrintFlagsInitial
1 2 3 4 5 6 7 8 9 10 11 |
cuzz@cuzz-pc:~/Project/demo$ java -XX:+PrintFlagsInitial [Global flags] intx ActiveProcessorCount = -1 {product} uintx AdaptiveSizeDecrementScaleFactor = 4 {product} uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} uintx AdaptiveSizePausePolicy = 0 {product} uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product} uintx AdaptiveSizePolicyInitializingSteps = 20 {product} uintx AdaptiveSizePolicyOutputInterval = 0 {product} uintx AdaptiveSizePolicyWeight = 10 {product} ... |
查看修改更新:-XX:+PrintFlagsFinal
1 2 3 4 5 6 7 |
bool UsePSAdaptiveSurvivorSizePolicy = true {product} bool UseParNewGC = false {product} bool UseParallelGC := true {product} bool UseParallelOldGC = true {product} bool UsePerfData = true {product} bool UsePopCountInstruction = true {product} bool UseRDPCForConstantTableBase = false {C2 product} |
= 與 := 的區別是,一個是默認,一個是人物改變或者 jvm 加載時改變的參數
打印命令行參數(能夠看默認垃圾回收器):-XX:+PrintCommandLineFlags
1 2 |
cuzz@cuzz-pc:~/Project/demo$ java -XX:+PrintCommandLineFlags -XX:InitialHeapSize=128789376 -XX:MaxHeapSize=2060630016 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC |
-XX:+PrintGCDetails
輸出詳細 GC 收集日誌信息
代碼
1 2 3 4 5 |
public class HelloGC { public static void main(String[] args) { byte[] bytes = new byte[20 * 1024 * 1024]; } } |
打印結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[GC (Allocation Failure) [PSYoungGen: 1231K->448K(2560K)] 1231K->456K(9728K), 0.0015616 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC (Allocation Failure) [PSYoungGen: 448K->384K(2560K)] 456K->392K(9728K), 0.0016999 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 384K->0K(2560K)] [ParOldGen: 8K->358K(7168K)] 392K->358K(9728K), [Metaspace: 3028K->3028K(1056768K)], 0.0066696 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 358K->358K(9728K), 0.0005321 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 358K->340K(7168K)] 358K->340K(9728K), [Metaspace: 3028K->3028K(1056768K)], 0.0051543 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] Heap PSYoungGen total 2560K, used 81K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000) eden space 2048K, 3% used [0x00000000ffd00000,0x00000000ffd14668,0x00000000fff00000) from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) ParOldGen total 7168K, used 340K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000) object space 7168K, 4% used [0x00000000ff600000,0x00000000ff655188,0x00000000ffd00000) Metaspace used 3060K, capacity 4496K, committed 4864K, reserved 1056768K class space used 336K, capacity 388K, committed 512K, reserved 1048576K Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.cuzz.jvm.HelloGC.main(HelloGC.java:12) |
-XX:MaxTenuringThreshold
在Java語言中,除了基本數據類型外,其餘的都是指向各種對象的對象引用;Java中根據其生命週期的長短,將引用分爲4類。
強引用
軟引用
代碼驗證
我設置 JVM 參數爲 -Xms10m -Xmx10m -XX:+PrintGCDetails
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class SoftReferenceDemo { public static void main(String[] args) { Object obj = new Object(); SoftReference<Object> softReference = new SoftReference<>(obj); obj = null; try { // 分配 20 M byte[] bytes = new byte[20 * 1024 * 1024]; } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("軟引用:" + softReference.get()); } } } |
輸出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[GC (Allocation Failure) [PSYoungGen: 1234K->448K(2560K)] 1234K->456K(9728K), 0.0016748 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 448K->384K(2560K)] 456K->392K(9728K), 0.0018398 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 384K->0K(2560K)] [ParOldGen: 8K->358K(7168K)] 392K->358K(9728K), [Metaspace: 3030K->3030K(1056768K)], 0.0057246 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 358K->358K(9728K), 0.0006038 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 358K->340K(7168K)] 358K->340K(9728K), [Metaspace: 3030K->3030K(1056768K)], 0.0115080 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 軟引用:null Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.cuzz.jvm.SoftReferenceDemo.main(SoftReferenceDemo.java:21) Heap PSYoungGen total 2560K, used 98K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000) eden space 2048K, 4% used [0x00000000ffd00000,0x00000000ffd18978,0x00000000fff00000) from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) ParOldGen total 7168K, used 340K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000) object space 7168K, 4% used [0x00000000ff600000,0x00000000ff6552f8,0x00000000ffd00000) Metaspace used 3067K, capacity 4496K, committed 4864K, reserved 1056768K class space used 336K, capacity 388K, committed 512K, reserved 1048576K |
發現當內存不夠的時候就會被回收。
弱引用
代碼驗證
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class WeakReferenceDemo { public static void main(String[] args) { Object obj = new Object(); WeakReference<Object> weakReference = new WeakReference<>(obj); System.out.println(obj); System.out.println(weakReference.get()); obj = null; System.gc(); System.out.println("GC以後...."); System.out.println(obj); System.out.println(weakReference.get()); } } |
輸出
1 2 3 4 5 |
java.lang.Object@1540e19d java.lang.Object@1540e19d GC以後.... null null |
值得注意的是String name = "cuzz"
這種會放入永久代,以及 Integer age = 1
在 int 中 -128 到 127 會被緩存,因此是強引用,而後 GC 也不會被回收。
引用隊列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class ReferenceQueueDemo { public static void main(String[] args) throws InterruptedException { Object obj = new Object(); ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); WeakReference<Object> weakReference = new WeakReference<>(obj, referenceQueue); System.out.println(obj); System.out.println(weakReference.get()); System.out.println(weakReference); obj = null; System.gc(); Thread.sleep(500); System.out.println("GC以後...."); System.out.println(obj); System.out.println(weakReference.get()); System.out.println(weakReference); } } |
輸出
1 2 3 4 5 6 7 |
java.lang.Object@1540e19d java.lang.Object@1540e19d java.lang.ref.WeakReference@677327b6 GC以後.... null null java.lang.ref.WeakReference@677327b6 |
會把該對象的包裝類即weakReference
放入到ReferenceQueue
裏面,咱們能夠從queue中獲取到相應的對象信息,同時進行額外的處理。好比反向操做,數據清理等。
java.lang.StackOverflowError
java.lang.OutOfMemoryError : Java heap space
java.lang.OutOfMemoryError : GC overhead limit exceeded
java.lang.OutOfMemoryError : Direct buffer memory
配置參數:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
1 2 3 4 5 6 |
public class DirectBufferDemo { public static void main(String[] args) { System.out.println("maxDirectMemory : " + sun.misc.VM.maxDirectMemory() / (1024 * 1024) + "MB"); ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024); } } |
輸出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
maxDirectMemory : 5MB [GC (System.gc()) [PSYoungGen: 1315K->464K(2560K)] 1315K->472K(9728K), 0.0008907 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [Full GC (System.gc()) [PSYoungGen: 464K->0K(2560K)] [ParOldGen: 8K->359K(7168K)] 472K->359K(9728K), [Metaspace: 3037K->3037K(1056768K)], 0.0060466 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:694) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at com.cuzz.jvm.DirectBufferDemo.main(DirectBufferDemo.java:17) Heap PSYoungGen total 2560K, used 56K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000) eden space 2048K, 2% used [0x00000000ffd00000,0x00000000ffd0e170,0x00000000fff00000) from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) ParOldGen total 7168K, used 359K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000) object space 7168K, 5% used [0x00000000ff600000,0x00000000ff659e28,0x00000000ffd00000) Metaspace used 3068K, capacity 4496K, committed 4864K, reserved 1056768K class space used 336K, capacity 388K, committed 512K, reserved 1048576K |
java.lang.OutOfMemoryError : unable to create new native thread
java.lang.OutOfMemoryError : Metaspace
具體的實現能夠看看這個帖子:幾種手動OOM的方式
老年代
垃圾收集器配置代碼總結
底層原理
Region 區域化垃圾收集器:最大好處是化整爲零,避免全內存掃描,只須要按照區域來進行掃描便可。
G1的內存結構和傳統的內存空間劃分有比較的不一樣。G1將內存劃分紅了多個大小相等的Region(默認是512K),Region邏輯上連續,物理內存地址不連續。同時每一個Region被標記成E、S、O、H,分別表示Eden、Survivor、Old、Humongous。其中E、S屬於年輕代,O與H屬於老年代。
H表示Humongous。從字面上就能夠理解表示大的對象(下面簡稱H對象)。當分配的對象大於等於Region大小的一半的時候就會被認爲是巨型對象。H對象默認分配在老年代,能夠防止GC的時候大對象的內存拷貝。經過若是發現堆內存容不下H對象的時候,會觸發一次GC操做。
下一篇重點介紹。