您好,登錄后才能下訂單哦!
這篇文章給大家介紹JVM中怎么判斷對(duì)象是否已死,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
/**
* 這個(gè)成員屬性的唯一意義就是占點(diǎn)內(nèi)存, 以便能在GC日志中看清楚是否有回收過
*/
private byte[] bigSize = new byte[2 * _1MB];
public static void main(String[] args) {
testGC();
}
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 假設(shè)在這行發(fā)生GC, objA和objB是否能被回收?
System.gc();
}
}
例子要說明的結(jié)果是,相互引用下卻已經(jīng)置為null的兩個(gè)對(duì)象,是否會(huì)被GC回收。如果只是按照引用計(jì)數(shù)器算法來看,那么這兩個(gè)對(duì)象的計(jì)數(shù)標(biāo)識(shí)不會(huì)為0,也就不能被回收。但到底有沒有被回收呢?
這里我們先采用 jvm 工具指令,jstat來監(jiān)控。因?yàn)楸O(jiān)控的過程需要我手敲代碼,比較耗時(shí),所以我們?cè)谡{(diào)用testGC()前,睡眠會(huì) Thread.sleep(55000);
。啟動(dòng)代碼后執(zhí)行如下指令。
E:\itstack\git\github.com\interview>jps -l
10656
88464
38372 org.itstack.interview.ReferenceCountingGC
26552 sun.tools.jps.Jps
110056 org.jetbrains.jps.cmdline.Launcher
E:\itstack\git\github.com\interview>jstat -gc 38372 2000
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 6561.4 175104.0 0.0 4480.0 770.9 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 1288.0 65536.0 0.0 175104.0 8.0 4864.0 3982.6 512.0 440.5 1 0.003 1 0.000 0.003
10752.0 10752.0 0.0 0.0 65536.0 437.3 175104.0 1125.5 4864.0 3982.6 512.0 440.5 1 0.003 1 0.012 0.015
10752.0 10752.0 0.0 0.0 65536.0 437.3 175104.0 1125.5 4864.0 3982.6 512.0 440.5 1 0.003 1 0.012 0.015
「注意」:觀察后面三行,S1U = 1288.0
、GCT = 0.003
,說明已經(jīng)在執(zhí)行垃圾回收。
接下來,我們?cè)贀Q種方式測(cè)試。在啟動(dòng)的程序中,加入GC打印參數(shù),觀察GC變化結(jié)果。
-XX:+PrintGCDetails 打印每次gc的回收情況 程序運(yùn)行結(jié)束后打印堆空間內(nèi)存信息(包含內(nèi)存溢出的情況)
-XX:+PrintHeapAtGC 打印每次gc前后的內(nèi)存情況
-XX:+PrintGCTimeStamps 打印每次gc的間隔的時(shí)間戳 full gc為每次對(duì)新生代老年代以及整個(gè)空間做統(tǒng)一的回收 系統(tǒng)中應(yīng)該盡量避免
-XX:+TraceClassLoading 打印類加載情況
-XX:+PrintClassHistogram 打印每個(gè)類的實(shí)例的內(nèi)存占用情況
-Xloggc:/Users/xiaofuge/Desktop/logs/log.log 配合上面的使用將上面的日志打印到指定文件
-XX:HeapDumpOnOutOfMemoryError 發(fā)生內(nèi)存溢出將堆信息轉(zhuǎn)存起來 以便分析
這回就可以把睡眠去掉了,并添加參數(shù) -XX:+PrintGCDetails
,如下:
「測(cè)試結(jié)果」
[GC (System.gc()) [PSYoungGen: 9346K->936K(76288K)] 9346K->944K(251392K), 0.0008518 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 936K->0K(76288K)] [ParOldGen: 8K->764K(175104K)] 944K->764K(251392K), [Metaspace: 3405K->3405K(1056768K)], 0.0040034 secs] [Times: user=0.08 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 76288K, used 1966K [0x000000076b500000, 0x0000000770a00000, 0x00000007c0000000)
eden space 65536K, 3% used [0x000000076b500000,0x000000076b6eb9e0,0x000000076f500000)
from space 10752K, 0% used [0x000000076f500000,0x000000076f500000,0x000000076ff80000)
to space 10752K, 0% used [0x000000076ff80000,0x000000076ff80000,0x0000000770a00000)
ParOldGen total 175104K, used 764K [0x00000006c1e00000, 0x00000006cc900000, 0x000000076b500000)
object space 175104K, 0% used [0x00000006c1e00000,0x00000006c1ebf100,0x00000006cc900000)
Metaspace used 3449K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 376K, capacity 388K, committed 512K, reserved 1048576K
「有了這個(gè)例子,我們?cè)俳又纯碕VM垃圾回收的知識(shí)框架!」
垃圾收集(Garbage Collection,簡稱GC),最早于1960年誕生于麻省理工學(xué)院的Lisp是第一門開始使用內(nèi)存動(dòng)態(tài)分配和垃圾收集技術(shù)的語言。
垃圾收集器主要做的三件事:哪些內(nèi)存需要回收
、什么時(shí)候回收
、怎么回收。
而從垃圾收集器的誕生到現(xiàn)在有半個(gè)世紀(jì)的發(fā)展,現(xiàn)在的內(nèi)存動(dòng)態(tài)分配和內(nèi)存回收技術(shù)已經(jīng)非常成熟,一切看起來都進(jìn)入了“自動(dòng)化”。但在某些時(shí)候還是需要我們?nèi)ケO(jiān)測(cè)在高并發(fā)的場(chǎng)景下,是否有內(nèi)存溢出、泄漏、GC時(shí)間過程等問題。所以在了解和知曉垃圾收集的相關(guān)知識(shí)對(duì)于高級(jí)程序員的成長就非常重要。
垃圾收集器的核心知識(shí)項(xiàng)主要包括:判斷對(duì)象是否存活、垃圾收集算法、各類垃圾收集器以及垃圾回收過程。如下圖;
原圖下載鏈接:http://book.bugstack.cn/#s/6jJp2icA
從實(shí)現(xiàn)來看,引用計(jì)數(shù)器法(Reference Counting)雖然占用了一些額外的內(nèi)存空間來進(jìn)行計(jì)數(shù),但是它的實(shí)現(xiàn)方案簡單,判斷效率高,是一個(gè)不錯(cuò)的算法。
也有一些比較出名的引用案例,比如:微軟COM(Component Object Model) 技術(shù)、使用ActionScript 3的FlashPlayer、 Python語言等。
「但是」,在主流的Java虛擬機(jī)中并沒有選用引用技術(shù)算法來管理內(nèi)存,主要是因?yàn)檫@個(gè)簡單的計(jì)數(shù)方式在處理一些相互依賴、循環(huán)引用等就會(huì)非常復(fù)雜??赡軙?huì)存在不再使用但又不能回收的內(nèi)存,造成內(nèi)存泄漏
Java、C#等主流語言的內(nèi)存管理子系統(tǒng),都是通過可達(dá)性分析(Reachability Analysis)算法來判定對(duì)象是否存活的。
它的算法思路是通過定義一系列稱為 GC Roots 根對(duì)象作為起始節(jié)點(diǎn)集,從這些節(jié)點(diǎn)出發(fā),窮舉該集合引用到的全部對(duì)象填充到該集合中(live set)。這個(gè)過程教過標(biāo)記,只標(biāo)記那些存活的對(duì)象 好,那么現(xiàn)在未被標(biāo)記的對(duì)象就是可以被回收的對(duì)象了。
GC Roots 包括;
「兩大問題」
關(guān)于JVM中怎么判斷對(duì)象是否已死就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。