網(wǎng)站做xss過濾seo快速排名軟件平臺(tái)
Java虛擬機(jī)(JVM)使用垃圾收集(Garbage Collection,GC)機(jī)制來自動(dòng)管理內(nèi)存,其中包括識(shí)別和回收不再使用的對(duì)象。JVM判定對(duì)象已經(jīng)“死去”(即不再被任何引用所指向)的過程主要基于以下幾個(gè)步驟:
1. 引用計(jì)數(shù)法:
這是一種簡單的垃圾收集算法,通過為每個(gè)對(duì)象維護(hù)一個(gè)引用計(jì)數(shù)來實(shí)現(xiàn)。每當(dāng)有一個(gè)新的引用指向該對(duì)象時(shí),計(jì)數(shù)增加;每當(dāng)一個(gè)引用被移除時(shí),計(jì)數(shù)減少。當(dāng)引用計(jì)數(shù)變?yōu)?時(shí),對(duì)象被認(rèn)為是“死去”的。然而,Java的JVM并不使用這種方法,因?yàn)樗荒芙鉀Q循環(huán)引用的問題。
下面V 哥介紹一下引用計(jì)數(shù)法的原理
引用計(jì)數(shù)法是一種簡單的垃圾收集算法,其基本原理是為每個(gè)對(duì)象維護(hù)一個(gè)計(jì)數(shù)器,用來記錄有多少個(gè)引用指向該對(duì)象。當(dāng)對(duì)象被創(chuàng)建時(shí),引用計(jì)數(shù)設(shè)置為1;每當(dāng)有一個(gè)新的引用指向該對(duì)象時(shí),計(jì)數(shù)器增加;每當(dāng)一個(gè)引用被移除時(shí),計(jì)數(shù)器減少。當(dāng)引用計(jì)數(shù)達(dá)到0時(shí),意味著沒有任何引用指向該對(duì)象,該對(duì)象就可以被垃圾收集器回收。
然而,Java虛擬機(jī)(JVM)并沒有采用引用計(jì)數(shù)法作為主要的垃圾收集策略,主要原因有:
-
循環(huán)引用問題:引用計(jì)數(shù)法無法處理循環(huán)引用的情況。如果兩個(gè)對(duì)象相互引用,即使它們不再被其他任何對(duì)象所引用,它們的引用計(jì)數(shù)也不會(huì)降到0,因此不會(huì)被回收。
-
性能問題:維護(hù)每個(gè)對(duì)象的引用計(jì)數(shù)器需要額外的內(nèi)存和處理時(shí)間,這可能會(huì)影響程序的性能。
-
線程安全問題:在多線程環(huán)境中,引用計(jì)數(shù)的更新需要同步,增加了實(shí)現(xiàn)的復(fù)雜性。
盡管JVM沒有采用引用計(jì)數(shù)法作為主要的垃圾收集策略,但它確實(shí)實(shí)現(xiàn)了一種變體,稱為“PhantomReference”(幻影引用)。PhantomReference是一種弱引用,它可以在對(duì)象被回收后進(jìn)行一些清理工作,但不會(huì)阻止對(duì)象的回收。以下是PhantomReference的實(shí)現(xiàn)步驟:
-
創(chuàng)建PhantomReference:開發(fā)者創(chuàng)建一個(gè)PhantomReference對(duì)象,將目標(biāo)對(duì)象和引用隊(duì)列作為參數(shù)傳遞。
-
注冊PhantomReference:將PhantomReference注冊到一個(gè)引用隊(duì)列中。當(dāng)垃圾收集器準(zhǔn)備回收目標(biāo)對(duì)象時(shí),會(huì)將PhantomReference放入引用隊(duì)列。
-
垃圾收集:當(dāng)垃圾收集器發(fā)現(xiàn)目標(biāo)對(duì)象的引用計(jì)數(shù)為0時(shí),會(huì)將其標(biāo)記為可回收。但是,它不會(huì)立即回收對(duì)象,而是將其放入一個(gè)待處理的列表中。
-
處理PhantomReference:當(dāng)垃圾收集器完成一輪垃圾收集后,會(huì)遍歷待處理的列表,將PhantomReference放入它們注冊的引用隊(duì)列中。
-
執(zhí)行清理工作:開發(fā)者可以在引用隊(duì)列中檢查是否有PhantomReference被放入,并執(zhí)行一些清理工作,例如關(guān)閉文件或網(wǎng)絡(luò)連接。
-
回收對(duì)象:在PhantomReference被處理之后,垃圾收集器最終會(huì)回收目標(biāo)對(duì)象占用的內(nèi)存。
PhantomReference提供了一種機(jī)制,允許開發(fā)者在對(duì)象被回收后執(zhí)行一些必要的清理工作,但它并不改變JVM主要的垃圾收集策略,即基于可達(dá)性分析的標(biāo)記-清除算法。
2. 可達(dá)性分析:
這是Java JVM實(shí)際使用的垃圾收集算法。從一系列被稱為"GC Roots"的對(duì)象開始,所有能夠從這些GC Roots直接或間接到達(dá)的對(duì)象都是活躍的。GC Roots通常包括:
- 棧中的局部變量
- 靜態(tài)變量
- 活動(dòng)線程的引用
- JNI全局引用
下面 V 哥介紹一下可達(dá)性分析的原理
可達(dá)性分析是Java虛擬機(jī)(JVM)中用于垃圾收集的一種算法,其核心原理是通過一系列被稱為GC Roots的對(duì)象開始,遍歷所有可達(dá)的對(duì)象,從而確定哪些對(duì)象是活躍的,哪些對(duì)象是不再被引用的(即“死去”的)。以下是可達(dá)性分析的詳細(xì)步驟:
- 選擇GC Roots:GC Roots是垃圾收集的起始點(diǎn),它們是一些特殊的對(duì)象,垃圾收集器認(rèn)為這些對(duì)象是活躍的。GC Roots包括:
- 棧中的局部變量
- 靜態(tài)字段(如靜態(tài)變量)
- 活動(dòng)線程
- JNI全局引用(Java Native Interface)
-
從GC Roots開始遍歷:垃圾收集器從GC Roots開始,遞歸地訪問所有能夠直接或間接到達(dá)的對(duì)象。
-
標(biāo)記階段:在遍歷過程中,垃圾收集器會(huì)標(biāo)記所有可達(dá)的對(duì)象。這些被標(biāo)記的對(duì)象被認(rèn)為是活躍的,不會(huì)被回收。
-
處理循環(huán)引用:可達(dá)性分析可以很好地處理循環(huán)引用問題。即使兩個(gè)對(duì)象相互引用,只要它們不是從GC Roots直接或間接可達(dá)的,它們的引用計(jì)數(shù)就不會(huì)增加,最終會(huì)被垃圾收集器回收。
-
識(shí)別不可訪問對(duì)象:在標(biāo)記階段結(jié)束后,所有未被標(biāo)記的對(duì)象被認(rèn)為是不可訪問的,即“死去”的,它們將被垃圾收集器回收。
-
清除階段:垃圾收集器會(huì)清除所有未被標(biāo)記的對(duì)象,釋放它們占用的內(nèi)存。這個(gè)過程可能涉及到內(nèi)存的整理,以避免內(nèi)存碎片。
-
回收內(nèi)存:最后,垃圾收集器會(huì)將回收的內(nèi)存重新納入可用內(nèi)存池中,供新的對(duì)象使用。
-
并發(fā)處理:在多線程環(huán)境中,JVM需要處理對(duì)象引用的變化和垃圾收集的并發(fā)問題。這通常通過使用寫屏障(Write Barrier)等技術(shù)來實(shí)現(xiàn),確保在引用修改時(shí),垃圾收集器能夠正確地識(shí)別對(duì)象的可達(dá)性。
-
垃圾收集器的選擇:JVM提供了多種垃圾收集器,它們在垃圾收集的效率和延遲方面有不同的權(quán)衡。開發(fā)者可以根據(jù)應(yīng)用的需求選擇合適的垃圾收集器。
可達(dá)性分析是一種高效的垃圾收集算法,它能夠準(zhǔn)確地識(shí)別出不再被引用的對(duì)象,同時(shí)處理循環(huán)引用問題,確保內(nèi)存的有效利用。然而,它也可能帶來一些性能開銷,尤其是在對(duì)象圖很大或者垃圾收集頻繁的情況下。因此,JVM提供了多種垃圾收集策略和算法,以適應(yīng)不同的應(yīng)用場景。
3. 標(biāo)記-清除:
在可達(dá)性分析之后,JVM會(huì)標(biāo)記所有從GC Roots可達(dá)的對(duì)象。然后,清除那些沒有被標(biāo)記的對(duì)象,這些對(duì)象被認(rèn)為是“死去”的。
下面 V 哥詳細(xì)介紹一下標(biāo)記-清除的原理
標(biāo)記-清除(Mark-Sweep)是一種常見的垃圾收集算法,它分為兩個(gè)主要階段:標(biāo)記階段和清除階段。以下是標(biāo)記-清除算法的原理和JVM實(shí)現(xiàn)的詳細(xì)步驟:
原理:
-
標(biāo)記階段:垃圾收集器遍歷所有對(duì)象,從GC Roots開始,標(biāo)記所有可達(dá)的對(duì)象。被標(biāo)記的對(duì)象被認(rèn)為是存活的,不會(huì)被回收。
-
清除階段:在標(biāo)記完成后,垃圾收集器遍歷堆內(nèi)存,識(shí)別出未被標(biāo)記的對(duì)象,這些對(duì)象被認(rèn)為是不再被引用的,隨后將這些對(duì)象的內(nèi)存釋放。
JVM實(shí)現(xiàn)步驟:
-
啟動(dòng)GC:JVM的垃圾收集器根據(jù)一定的條件(如內(nèi)存使用達(dá)到一定閾值)觸發(fā)垃圾收集過程。
-
標(biāo)記階段:
- 從GC Roots開始,遞歸遍歷所有可達(dá)對(duì)象。
- 為每個(gè)可達(dá)對(duì)象設(shè)置一個(gè)標(biāo)記,表明它們是活躍的。
-
處理并發(fā):在多線程環(huán)境中,JVM需要處理垃圾收集過程中對(duì)象引用的變化。這通常通過寫屏障(Write Barrier)來實(shí)現(xiàn),確保在引用修改時(shí),垃圾收集器能夠正確地識(shí)別對(duì)象的可達(dá)性。
-
暫停用戶線程:在標(biāo)記階段,JVM可能會(huì)暫停所有用戶線程,以確保標(biāo)記過程的準(zhǔn)確性。這是所謂的“Stop-the-World”事件。
-
清除階段:
- 完成標(biāo)記后,垃圾收集器開始清除未被標(biāo)記的對(duì)象。
- 釋放這些對(duì)象占用的內(nèi)存。
-
處理內(nèi)存碎片:清除過程可能會(huì)導(dǎo)致內(nèi)存碎片。JVM可能會(huì)在這個(gè)階段進(jìn)行內(nèi)存整理,以優(yōu)化內(nèi)存使用。
-
恢復(fù)用戶線程:清除完成后,JVM恢復(fù)之前暫停的用戶線程,讓它們繼續(xù)執(zhí)行。
-
并發(fā)清除:在某些情況下,JVM的垃圾收集器可能會(huì)嘗試并發(fā)執(zhí)行標(biāo)記和清除階段,以減少對(duì)應(yīng)用程序性能的影響。
-
優(yōu)化和選擇:JVM提供了多種垃圾收集器,它們在標(biāo)記-清除算法的基礎(chǔ)上進(jìn)行了優(yōu)化,以適應(yīng)不同的應(yīng)用場景和性能需求。
缺點(diǎn):
- 內(nèi)存碎片:標(biāo)記-清除算法可能會(huì)導(dǎo)致內(nèi)存碎片,因?yàn)閷?duì)象被逐個(gè)清除,而不是成塊清除。
- 效率問題:在標(biāo)記和清除階段,JVM可能需要暫停應(yīng)用程序的執(zhí)行,這在某些情況下會(huì)影響性能。
為了解決這些問題,JVM采用了其他算法,如復(fù)制算法(Copying),標(biāo)記-整理算法(Mark-Compact),以及分代收集策略等,以提高垃圾收集的效率和減少對(duì)應(yīng)用程序性能的影響。
4. 清除過程:
清除過程可能涉及到對(duì)象的內(nèi)存釋放和內(nèi)存碎片的整理。這個(gè)過程可能在不同的GC算法中有所不同,例如標(biāo)記-清除、復(fù)制算法、標(biāo)記-整理算法等。
下面來詳細(xì)介紹一下清除過程
清除過程是垃圾收集(Garbage Collection,GC)中的一個(gè)關(guān)鍵步驟,它發(fā)生在標(biāo)記階段之后。清除過程的目的是移除那些不再被引用的對(duì)象,從而回收它們占用的內(nèi)存。以下是清除過程的原理和JVM實(shí)現(xiàn)的詳細(xì)步驟:
原理:
清除過程的目標(biāo)是高效地回收不再被使用的內(nèi)存。這個(gè)過程通常涉及以下步驟:
-
識(shí)別未標(biāo)記對(duì)象:在標(biāo)記階段結(jié)束后,所有未被標(biāo)記的對(duì)象被認(rèn)為是垃圾,即不再被任何引用所指向。
-
回收內(nèi)存:垃圾收集器將這些未標(biāo)記對(duì)象占用的內(nèi)存釋放,使其成為可用內(nèi)存。
-
處理內(nèi)存碎片:清除過程中可能會(huì)產(chǎn)生內(nèi)存碎片。為了優(yōu)化內(nèi)存使用,可能需要進(jìn)行內(nèi)存整理。
JVM實(shí)現(xiàn)步驟:
-
觸發(fā)GC:當(dāng)JVM檢測到內(nèi)存使用達(dá)到一定閾值或滿足其他GC觸發(fā)條件時(shí),開始執(zhí)行垃圾收集。
-
標(biāo)記階段:從GC Roots開始,遞歸地標(biāo)記所有可達(dá)的對(duì)象。這一階段結(jié)束后,所有未被標(biāo)記的對(duì)象都是垃圾。
-
用戶線程暫停:在清除階段開始之前,JVM可能會(huì)暫停所有用戶線程,以確保清除過程不會(huì)與應(yīng)用程序的執(zhí)行發(fā)生沖突。
-
清除未標(biāo)記對(duì)象:
- 垃圾收集器遍歷堆內(nèi)存,識(shí)別出未被標(biāo)記的對(duì)象。
- 將這些對(duì)象的內(nèi)存釋放,使其成為可用內(nèi)存。
- 處理內(nèi)存碎片:清除后可能會(huì)產(chǎn)生內(nèi)存碎片。JVM可以通過以下方式處理:
- 內(nèi)存整理:移動(dòng)存活對(duì)象,將它們緊湊地排列在一起,減少碎片。
- 內(nèi)存壓縮:在某些GC算法中,如標(biāo)記-整理(Mark-Compact)算法,會(huì)重新排列對(duì)象來減少碎片。
-
恢復(fù)用戶線程:清除完成后,JVM恢復(fù)之前暫停的用戶線程,讓它們繼續(xù)執(zhí)行。
-
并發(fā)清除:在某些垃圾收集器中,清除過程可以與應(yīng)用程序的執(zhí)行并發(fā)進(jìn)行,以減少對(duì)性能的影響。
-
選擇垃圾收集器:JVM提供了多種垃圾收集器,它們在清除算法的實(shí)現(xiàn)上有所不同,以適應(yīng)不同的應(yīng)用場景和性能需求。
-
優(yōu)化和調(diào)整:JVM的垃圾收集器會(huì)根據(jù)應(yīng)用程序的行為和性能反饋進(jìn)行優(yōu)化和調(diào)整,以提高垃圾收集的效率。
清除過程是垃圾收集中的關(guān)鍵環(huán)節(jié),它直接影響到內(nèi)存的回收效率和應(yīng)用程序的性能。JVM通過多種策略和技術(shù)來優(yōu)化清除過程,以確保內(nèi)存的有效利用和應(yīng)用程序的流暢執(zhí)行。
5. 回收:
最后,JVM會(huì)回收那些被標(biāo)記為“死去”的對(duì)象所占用的內(nèi)存,并將這些內(nèi)存重新納入可用內(nèi)存池中,供新的對(duì)象使用。
下面是 V 哥的詳細(xì)介紹和理解
回收是垃圾收集(Garbage Collection,GC)的最終目標(biāo),即釋放不再被使用的內(nèi)存資源。在JVM中,回收的原理和實(shí)現(xiàn)步驟如下:
原理:
-
識(shí)別垃圾:通過垃圾收集算法(如標(biāo)記-清除、復(fù)制、標(biāo)記-整理等)識(shí)別出不再被引用的對(duì)象。
-
釋放內(nèi)存:將這些垃圾對(duì)象占用的內(nèi)存釋放,使其可以被JVM重新利用。
-
內(nèi)存管理:確保內(nèi)存的高效使用,避免內(nèi)存碎片,優(yōu)化內(nèi)存分配策略。
JVM實(shí)現(xiàn)步驟:
-
觸發(fā)GC:JVM根據(jù)內(nèi)存使用情況或特定的GC觸發(fā)條件,啟動(dòng)垃圾收集過程。
-
選擇GC Roots:確定GC Roots,這些是垃圾收集的起始點(diǎn),包括棧中的局部變量、靜態(tài)變量、JNI全局引用等。
-
可達(dá)性分析:從GC Roots開始,進(jìn)行可達(dá)性分析,標(biāo)記所有可達(dá)的對(duì)象。
-
標(biāo)記階段:遍歷對(duì)象圖,標(biāo)記所有可達(dá)的對(duì)象,未被標(biāo)記的對(duì)象被認(rèn)為是垃圾。
-
用戶線程暫停:在某些GC算法中,可能需要暫停用戶線程以保證GC的準(zhǔn)確性。
-
回收階段:
- 清除未標(biāo)記的對(duì)象,釋放它們占用的內(nèi)存。
- 處理內(nèi)存碎片,可能通過內(nèi)存整理或壓縮來優(yōu)化內(nèi)存布局。
-
內(nèi)存整理:在某些GC算法中,如標(biāo)記-整理算法,會(huì)移動(dòng)存活對(duì)象,減少內(nèi)存碎片。
-
恢復(fù)用戶線程:GC完成后,恢復(fù)用戶線程的執(zhí)行。
-
并發(fā)收集:在并發(fā)GC算法中,部分GC工作可以與用戶線程并發(fā)執(zhí)行,以減少停頓時(shí)間。
-
內(nèi)存分配:回收的內(nèi)存被納入空閑內(nèi)存池,供新對(duì)象分配使用。
-
化和調(diào)整:JVM的垃圾收集器會(huì)根據(jù)應(yīng)用程序的行為和性能反饋進(jìn)行優(yōu)化和調(diào)整。
-
選擇垃圾收集器:JVM提供了多種垃圾收集器,每種收集器針對(duì)不同的應(yīng)用場景和性能需求,有不同的回收策略。
回收策略:
-
分代收集:JVM通常將堆內(nèi)存分為新生代和老年代,采用不同的收集策略。新生代使用復(fù)制算法,老年代可能使用標(biāo)記-清除或標(biāo)記-整理算法。
-
并發(fā)收集:一些垃圾收集器(如G1、ZGC、Shenandoah)支持并發(fā)收集,減少GC對(duì)應(yīng)用程序性能的影響。
-
增量收集:通過分步驟執(zhí)行GC,減少單次GC的停頓時(shí)間。
-
實(shí)時(shí)收集:某些垃圾收集器(如Real-Time Collector)旨在提供可預(yù)測的低延遲GC。
通過這些策略,JVM能夠有效地管理內(nèi)存,確保應(yīng)用程序的高效運(yùn)行。垃圾收集是JVM性能調(diào)優(yōu)的重要組成部分,開發(fā)者需要根據(jù)應(yīng)用程序的特點(diǎn)選擇合適的垃圾收集器和參數(shù)。
5. 并發(fā)問題:
在多線程環(huán)境中,JVM還需要處理對(duì)象引用的變化和垃圾收集的并發(fā)問題。這通常通過使用寫屏障(Write Barrier)等技術(shù)來實(shí)現(xiàn)。
在多線程環(huán)境中,垃圾收集(Garbage Collection,GC)需要處理并發(fā)問題,以確保在進(jìn)行內(nèi)存回收的同時(shí),應(yīng)用程序的其他線程可以繼續(xù)執(zhí)行,并且不會(huì)干擾垃圾收集器的工作。以下是并發(fā)問題的原理和JVM處理這些并發(fā)問題的步驟:
并發(fā)問題的原理:
-
對(duì)象引用變化:在多線程環(huán)境中,對(duì)象的引用可能隨時(shí)發(fā)生變化。一個(gè)對(duì)象可能在一個(gè)線程中被引用,而在另一個(gè)線程中被取消引用。
-
內(nèi)存一致性:需要保證在多線程環(huán)境下,內(nèi)存操作的可見性和順序性,確保垃圾收集器能夠看到最新的對(duì)象引用狀態(tài)。
-
避免Stop-the-World:長時(shí)間的GC停頓(Stop-the-World)會(huì)影響應(yīng)用程序的響應(yīng)時(shí)間和吞吐量。
6. 垃圾收集器的選擇:
JVM提供了多種垃圾收集器,它們在垃圾收集的效率和延遲方面有不同的權(quán)衡。開發(fā)者可以根據(jù)應(yīng)用的需求選擇合適的垃圾收集器。
選擇垃圾收集器的策略需要考慮多個(gè)因素,包括應(yīng)用程序的特點(diǎn)、預(yù)期的性能目標(biāo)、硬件環(huán)境等。以下是一些常見的選擇策略和考慮因素,結(jié)合了不同應(yīng)用場景的需求:
-
吞吐量優(yōu)先:如果應(yīng)用程序的目標(biāo)是最大化CPU的利用率,即盡可能減少垃圾收集時(shí)間,提高應(yīng)用程序的吞吐量,可以選擇如Parallel Scavenge或G1這樣的收集器。
-
低延遲優(yōu)先:對(duì)于需要快速響應(yīng)用戶請(qǐng)求的應(yīng)用程序,如Web應(yīng)用或交易系統(tǒng),可以選擇CMS或G1收集器,這些收集器的設(shè)計(jì)目標(biāo)是減少GC引起的停頓時(shí)間。
-
大堆內(nèi)存管理:對(duì)于擁有大堆內(nèi)存的應(yīng)用程序,G1收集器是一個(gè)不錯(cuò)的選擇,因?yàn)樗梢院芎玫靥幚泶蠖巡⑶彝nD時(shí)間可控。
-
內(nèi)存占用考慮:在內(nèi)存資源受限的環(huán)境中,Serial收集器可能是一個(gè)好選擇,尤其是對(duì)于單核處理器或小型應(yīng)用。
-
多核CPU利用:對(duì)于多核CPU系統(tǒng),可以利用并行或并發(fā)收集器,如Parallel Scavenge、Parallel Old或G1,這些收集器可以有效地利用多核處理器的計(jì)算能力。
-
應(yīng)用的交互性:對(duì)于需要高交互性的應(yīng)用程序,應(yīng)選擇能夠提供快速響應(yīng)的收集器,如CMS,以保持較好的用戶體驗(yàn)。
-
硬件環(huán)境:考慮服務(wù)器的CPU核心數(shù)和內(nèi)存大小,選擇與之相匹配的收集器。例如,Parallel Scavenge和Parallel Old適合多核服務(wù)器。
-
JVM默認(rèn)設(shè)置:了解不同JDK版本下的默認(rèn)垃圾收集器,如JDK 1.9中G1成為默認(rèn)收集器,并根據(jù)需要進(jìn)行調(diào)整。
-
性能測試和監(jiān)控:通過性能測試和監(jiān)控來評(píng)估不同收集器的效果,根據(jù)實(shí)際運(yùn)行情況選擇最合適的收集器。
-
JVM參數(shù)調(diào)優(yōu):使用JVM參數(shù)來指定垃圾收集器,并根據(jù)應(yīng)用程序的需要進(jìn)行調(diào)優(yōu),如設(shè)置最大GC停頓時(shí)間或調(diào)整堆大小。
選擇垃圾收集器并沒有一勞永逸的解決方案,通常需要根據(jù)具體的應(yīng)用場景和性能要求進(jìn)行綜合評(píng)估和調(diào)整。通過理解每種收集器的特點(diǎn)和工作原理,可以更好地進(jìn)行性能調(diào)優(yōu)和選擇合適的垃圾收集器。
最后
JVM通過一系列復(fù)雜的機(jī)制來判定對(duì)象是否“死去”,并進(jìn)行垃圾收集,以確保內(nèi)存的有效利用和避免內(nèi)存泄漏。