Java垃圾回收的示例分析-創(chuàng)新互聯(lián)

這篇文章將為大家詳細(xì)講解有關(guān)Java垃圾回收的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

成都創(chuàng)新互聯(lián)公司主營白沙黎族網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app軟件開發(fā)公司,白沙黎族h5成都小程序開發(fā)搭建,白沙黎族網(wǎng)站營銷推廣歡迎白沙黎族等地區(qū)企業(yè)咨詢

Java垃圾回收是一項自動化的過程,用來管理程序所使用的運行時內(nèi)存。通過這一自動化過程,JVM解除了程序員在程序中分配和釋放內(nèi)存資源的開銷。

啟動Java垃圾回收

作為一個自動的過程,程序員不需要在代碼中顯示地啟動垃圾回收過程。System.gc()和Runtime.gc()用來請求JVM啟動垃圾回收。

雖然這個請求機(jī)制提供給程序員一個啟動GC過程的機(jī)會,但是啟動由JVM負(fù)責(zé)。JVM可以拒絕這個請求,所以并不保證這些調(diào)用都將執(zhí)行垃圾回收。啟動時機(jī)的選擇由JVM決定,并且取決于堆內(nèi)存中Eden區(qū)是否可用。JVM將這個選擇留給了Java規(guī)范的實現(xiàn),不同實現(xiàn)具體使用的算法不盡相同。

毋庸置疑,我們知道垃圾回收過程是不能被強(qiáng)制執(zhí)行的。我剛剛發(fā)現(xiàn)了一個調(diào)用System.gc()有意義的場景。通過這篇文章了解一下適合調(diào)用System.gc()這種極端情況。

Java垃圾回收過程

垃圾回收是一種回收無用內(nèi)存空間并使其對未來實例可用的過程。

Java垃圾回收的示例分析

Eden區(qū):當(dāng)一個實例被創(chuàng)建了,首先會被存儲在堆內(nèi)存年輕代的Eden區(qū)中。

注意:如果你不能理解這些詞匯,我建議你閱讀這篇垃圾回收介紹,這篇教程詳細(xì)地介紹了內(nèi)存模型、JVM架構(gòu)以及這些術(shù)語。

Survivor區(qū)(S0和S1):作為年輕代GC(MinorGC)周期的一部分,存活的對象(仍然被引用的)從Eden區(qū)被移動到Survivor區(qū)的S0中。類似的,垃圾回收器會掃描S0然后將存活的實例移動到S1中。

(譯注:此處不應(yīng)該是Eden和S0中存活的都移到S1么,為什么會先移到S0再從S0移到S1?)

死亡的實例(不再被引用)被標(biāo)記為垃圾回收。根據(jù)垃圾回收器(有四種常用的垃圾回收器,將在下一教程中介紹它們)選擇的不同,要么被標(biāo)記的實例都會不停地從內(nèi)存中移除,要么回收過程會在一個單獨的進(jìn)程中完成。

老年代:老年代(Oldortenuredgeneration)是堆內(nèi)存中的第二塊邏輯區(qū)。當(dāng)垃圾回收器執(zhí)行MinorGC周期時,在S1Survivor區(qū)中的存活實例將會被晉升到老年代,而未被引用的對象被標(biāo)記為回收。

老年代GC(MajorGC):相對于Java垃圾回收過程,老年代是實例生命周期的最后階段。MajorGC掃描老年代的垃圾回收過程。如果實例不再被引用,那么它們會被標(biāo)記為回收,否則它們會繼續(xù)留在老年代中。

內(nèi)存碎片:一旦實例從堆內(nèi)存中被刪除,其位置就會變空并且可用于未來實例的分配。這些空出的空間將會使整個內(nèi)存區(qū)域碎片化。為了實例的快速分配,需要進(jìn)行碎片整理?;诶厥掌鞯牟煌x擇,回收的內(nèi)存區(qū)域要么被不停地被整理,要么在一個單獨的GC進(jìn)程中完成。

垃圾回收中實例的終結(jié)

在釋放一個實例和回收內(nèi)存空間之前,Java垃圾回收器會調(diào)用實例各自的finalize()方法,從而該實例有機(jī)會釋放所持有的資源。雖然可以保證finalize()會在回收內(nèi)存空間之前被調(diào)用,但是沒有指定的順序和時間。多個實例間的順序是無法被預(yù)知,甚至可能會并行發(fā)生。程序不應(yīng)該預(yù)先調(diào)整實例之間的順序并使用finalize()方法回收資源。

任何在finalize過程中未被捕獲的異常會自動被忽略,然后該實例的finalize過程被取消。

JVM規(guī)范中并沒有討論關(guān)于弱引用的垃圾回收機(jī)制,也沒有很明確的要求。具體的實現(xiàn)都由實現(xiàn)方?jīng)Q定。

垃圾回收是由一個守護(hù)線程完成的。

對象什么時候符合垃圾回收的條件?

所有實例都沒有活動線程訪問。

沒有被其他任何實例訪問的循環(huán)引用實例。

Java中有不同的引用類型。判斷實例是否符合垃圾收集的條件都依賴于它的引用類型。

引用類型垃圾收集
強(qiáng)引用(Strong Reference)不符合垃圾收集
軟引用(Soft Reference)垃圾收集可能會執(zhí)行,但會作為最后的選擇
弱引用(Weak Reference)符合垃圾收集
虛引用(Phantom Reference)符合垃圾收集

在編譯過程中作為一種優(yōu)化技術(shù),Java 編譯器能選擇給實例賦 null 值,從而標(biāo)記實例為可回收。

class Animal {
  public static void main(String[] args) {
    Animal lion = new Animal();
    System.out.println("Main is completed.");
  }
 
  protected void finalize() {
    System.out.println("Rest in Peace!");
  }
}

在上面的類中,lion對象在實例化行后從未被使用過。因此Java編譯器作為一種優(yōu)化措施可以直接在實例化行后賦值lion=null。因此,即使在SOP輸出之前,finalize函數(shù)也能夠打印出'RestinPeace!'。我們不能證明這確定會發(fā)生,因為它依賴JVM的實現(xiàn)方式和運行時使用的內(nèi)存。然而,我們還能學(xué)習(xí)到一點:如果編譯器看到該實例在未來再也不會被引用,能夠選擇并提早釋放實例空間。

關(guān)于對象什么時候符合垃圾回收有一個更好的例子。實例的所有屬性能被存儲在寄存器中,隨后寄存器將被訪問并讀取內(nèi)容。無一例外,這些值將被寫回到實例中。雖然這些值在將來能被使用,這個實例仍然能被標(biāo)記為符合垃圾回收。這是一個很經(jīng)典的例子,不是嗎?

當(dāng)被賦值為null時,這是很簡單的一個符合垃圾回收的示例。當(dāng)然,復(fù)雜的情況可以像上面的幾點。這是由JVM實現(xiàn)者所做的選擇。目的是留下盡可能小的內(nèi)存占用,加快響應(yīng)速度,提高吞吐量。為了實現(xiàn)這一目標(biāo),JVM的實現(xiàn)者可以選擇一個更好的方案或算法在垃圾回收過程中回收內(nèi)存空間。

當(dāng)finalize()方法被調(diào)用時,JVM會釋放該線程上的所有同步鎖。

GCScope示例程序

Class GCScope {
	GCScope t;
	static int i = 1;
	public static void main(String args[]) {
		GCScope t1 = new GCScope();
		GCScope t2 = new GCScope();
		GCScope t3 = new GCScope();
		// No Object Is Eligible for GC
		t1.t = t2;
		// No Object Is Eligible for GC
		t2.t = t3;
		// No Object Is Eligible for GC
		t3.t = t1;
		// No Object Is Eligible for GC
		t1 = null;
		// No Object Is Eligible for GC (t3.t still has a reference to t1)
		t2 = null;
		// No Object Is Eligible for GC (t3.t.t still has a reference to t2)
		t3 = null;
		// All the 3 Object Is Eligible for GC (None of them have a reference.
		// only the variable t of the objects are referring each other in a
		// rounded fashion forming the Island of objects with out any external
		// reference)
	}
	protected void finalize() {
		System.out.println("Garbage collected from object" + i);
		i++;
	}
	class GCScope {
		GCScope t;
		static int i = 1;
		public static void main(String args[]) {
			GCScope t1 = new GCScope();
			GCScope t2 = new GCScope();
			GCScope t3 = new GCScope();
			// 沒有對象符合GC
			t1.t = t2;
			// 沒有對象符合GC
			t2.t = t3;
			// 沒有對象符合GC
			t3.t = t1;
			// 沒有對象符合GC
			t1 = null;
			// 沒有對象符合GC (t3.t 仍然有一個到 t1 的引用)
			t2 = null;
			// 沒有對象符合GC (t3.t.t 仍然有一個到 t2 的引用)
			t3 = null;
			// 所有三個對象都符合GC (它們中沒有一個擁有引用。
			// 只有各對象的變量 t 還指向了彼此,
			// 形成了一個由對象組成的環(huán)形的島,而沒有任何外部的引用。)
		}
		protected void finalize() {
			System.out.println("Garbage collected from object" + i);
			i++;
		}

GC OutOfMemoryError 的示例程序

GC并不保證內(nèi)存溢出問題的安全性,粗心寫下的代碼會導(dǎo)致 OutOfMemoryError。

import java.util.LinkedList;
import java.util.List;
public class GC {
	public static void main(String[] main) {
		List l = new LinkedList();
		// Enter infinite loop which will add a String to the list: l on each
		// iteration.
		do {
			l.add(new String("Hello, World"));
		}
		while (true);
	}
}

輸出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  at java.util.LinkedList.linkLast(LinkedList.java:142)
  at java.util.LinkedList.add(LinkedList.java:338)
  at com.javapapers.java.GCScope.main(GCScope.java:12)

關(guān)于“Java垃圾回收的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

網(wǎng)頁名稱:Java垃圾回收的示例分析-創(chuàng)新互聯(lián)
路徑分享:http://muchs.cn/article18/cddsgp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、定制網(wǎng)站、網(wǎng)站營銷關(guān)鍵詞優(yōu)化、定制開發(fā)、手機(jī)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)