摘要:當(dāng)一個實(shí)例被創(chuàng)建的時候,它最初被存放在堆內(nèi)存空間的年輕代的區(qū)中。老年代或者永久代是堆內(nèi)存的第二個邏輯部分。在垃圾回收過程中掃描屬于部分的堆內(nèi)存。一旦實(shí)例從堆內(nèi)存中刪除了,它們原來的位置將空出來給以后分配實(shí)例使用。
本文非原創(chuàng),翻譯自How Java Garbage Collection Works?
在Java中為對象分配和釋放內(nèi)存空間都是由垃圾回收線程自動執(zhí)行完成的。和C語言不一樣的是Java程序員不需要手動寫垃圾回收相關(guān)的代碼。這是使得Java如此流行,同時也是Java能幫助程序員寫出更好的Java應(yīng)用的優(yōu)點(diǎn)之一。
這是垃圾回收機(jī)制系列文章的第二篇。希望您已經(jīng)讀過了第一部分Java垃圾回收簡介.
Java垃圾回收是一個自動運(yùn)行的管理程序運(yùn)行時使用的內(nèi)存的進(jìn)程。通過GC的自動執(zhí)行JVM將程序員從申請和釋放內(nèi)存的繁重操作中解放出來。
Java垃圾回收GC初始化作為一個自動執(zhí)行的進(jìn)程,程序員不需要在代碼中主動初始化GC。Java提供了System.gc()和Runtime.gc()這兩個hook來請求JVM調(diào)用GC進(jìn)程。
盡管要求系統(tǒng)機(jī)制給程序員提供調(diào)用GC的機(jī)會,但是實(shí)際上這是由JVM負(fù)責(zé)決定的。JVM可以選擇拒絕啟動GC的請求,因此并不保證這些請求會真的調(diào)用垃圾回收。這是JVM基于內(nèi)存堆空間的Eden區(qū)的使用情況做出的決定。JVM規(guī)范將這個選擇權(quán)利留給了各個JVM的具體實(shí)現(xiàn),因此實(shí)際上JVM是如何選擇的視不同JVM的實(shí)現(xiàn)而定(不過要記住的是,不能依賴于這兩個方法的調(diào)用,它們是不被保證執(zhí)行的)。
毫無疑問的是,我們知道垃圾回收進(jìn)程是不能強(qiáng)制執(zhí)行的。不過我剛發(fā)現(xiàn)一個調(diào)用System.gc()確實(shí)有意義的場景。看下這篇文章你就會了解System.gc()調(diào)用是可用的這個特殊的場景。
Java 垃圾回收進(jìn)程垃圾回收是一個回收不再使用的內(nèi)存空間并將它變成能夠?yàn)閷淼膶?shí)例使用的過程。
Eden Space:當(dāng)一個實(shí)例被創(chuàng)建的時候,它最初被存放在堆內(nèi)存空間的年輕代的Eden區(qū)中。
注意:如果您不太理解這些術(shù)語,建議您先看下介紹內(nèi)存模型、JVM架構(gòu)及這些術(shù)語的詳細(xì)解釋的文章:garbage-collection-introduction-tutorial
Survivor Space(S0 和S1):作為minor回收周期的一部分,還活著的對象(還有引用指向它)被從eden區(qū)中移動到survivor空間S0。同樣的,垃圾回收器掃描S0并將活著的實(shí)例移動到S1。
無用的對象(沒有引用指向)被標(biāo)記并回收。垃圾回收器(有四種可用的垃圾回收器,將在下一篇文章中介紹)決定這些被標(biāo)記的實(shí)例是在掃描的過程中移出內(nèi)存還是在另外獨(dú)立的遷移進(jìn)程中執(zhí)行。
Old Generation:老年代或者永久代是堆內(nèi)存的第二個邏輯部分。當(dāng)垃圾回收器在做minor GC周期中,S1 survivor區(qū)中還活著的實(shí)例會被提升到老年代中。S1區(qū)中不再被引用的對象被標(biāo)記并清除。
Major GC:在Java垃圾回收過程中實(shí)例生命周期的最后一個階段。Major GC在垃圾回收過程中掃描屬于Old Generation部分的堆內(nèi)存。如果實(shí)例沒有被任何引用關(guān)聯(lián),它們將被標(biāo)記、清除;如果它們還被引用關(guān)聯(lián)著,則將繼續(xù)存留在old generation。
垃圾回收過程中的對象銷毀–FinalizationMemory
Fragmentation:一旦實(shí)例從堆內(nèi)存中刪除了,它們原來的位置將空出來給以后分配實(shí)例使用。顯然這些空閑空間很容易在內(nèi)存空間中產(chǎn)生碎片。為了能夠更快地分配實(shí)例地址,需要對內(nèi)存做去碎片化操作。根據(jù)不同垃圾回收器的策略,被回收的內(nèi)存將在回收的過程同時或者在GC另外獨(dú)立的過程中壓縮整合。
就在移除一個對象并回收它的內(nèi)存空間之前,Java垃圾回收器將會調(diào)用各個實(shí)例的finalize()方法,這樣實(shí)例對象就有機(jī)會可以釋放掉它占用的資源。盡管finalize()方法是保證在回收內(nèi)存空間之前執(zhí)行的,但是對具體的執(zhí)行時間和執(zhí)行順序是沒有任何保證的。多個實(shí)例之間的finalize()執(zhí)行順序是不能提前預(yù)知的,甚至有可能它們是并行執(zhí)行的。程序不應(yīng)該預(yù)先假設(shè)實(shí)例執(zhí)行finalize()的方法,也不應(yīng)該使用finalize()方法來回收資源。
在finalize過程中拋出的任何異常都默認(rèn)被忽略掉了,同時對象的銷毀過程被取消
JVM規(guī)范并沒有討論關(guān)于弱引用的垃圾回收,這是明確聲明的。具體的細(xì)節(jié)留給實(shí)現(xiàn)者決定。
垃圾回收是由守護(hù)進(jìn)程執(zhí)行的
對象何時變成可被垃圾回收的?所有不能被活著的線程到達(dá)實(shí)例
不能被其他對象到達(dá)的循環(huán)引用對象 Java中有多種不同的引用類型。實(shí)例的可回收性取決于它的引用類型。
Reference | Garbage Collection |
---|---|
Strong Refrence | 不被垃圾回收 |
Soft Reference | 作為最后的選擇,有可能被回收 |
Weak Reference | 可以被垃圾回收 |
Phantom Reference | 可以被垃圾回收 |
在編譯過程中Java編譯器有個優(yōu)化機(jī)制,編譯器可以選擇將null賦值給一個實(shí)例,這樣就將這個實(shí)例標(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!"); } }
在上面這個類中,實(shí)例lion在除了初始化那一行在其他地方都沒有被使用到。因此作為一種優(yōu)化方法,Java編譯器可以在初始化那一行后面立即賦值lion = null。這樣finlizer可能會在Main方法的SOP之前打印結(jié)果。
Rest in Peace! Main is completed.
但結(jié)果的順序是不確定的,它取決于JVM的實(shí)現(xiàn)以及運(yùn)行時的內(nèi)存使用情況。從中我們能知道的一點(diǎn)是:編譯器在發(fā)現(xiàn)一個實(shí)例的之后的程序中不再被引用時可以選擇提前釋放實(shí)例內(nèi)存。
這里有個實(shí)例何時變成可回收更好的例子。實(shí)例所有的屬性可以被存儲在寄存器中之后可以從寄存器中讀取這些屬性值,且未來在任何情況下都不會將值寫回到實(shí)例對象中。這樣盡管這個實(shí)例在未來還是被使用到了,但是實(shí)例對象依然可以被標(biāo)記為可回收的。
何時能被垃圾回收可以簡單到僅僅認(rèn)為在賦值為null的時候也可以復(fù)雜到如上面那一點(diǎn)所說的那樣。JVM的實(shí)現(xiàn)者會做一些取舍。其目標(biāo)都是希望留下最少的痕跡,提高響應(yīng)時間增大吞吐量。為了能夠達(dá)到這些目的,JVM實(shí)現(xiàn)者可以在垃圾回收中選擇更好的模式或算法來回收內(nèi)存。
當(dāng)finalize()被調(diào)用的時候,JVM釋放掉當(dāng)前線程的所有同步塊。
Example Program for GC Scope
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;//所有3個對象都可以被GC(沒有一個被引用了) //只有各個對象的變量t互相循環(huán)引用形成了一個孤立的引用環(huán),而沒有外部引用 } protected void finalize() { System.out.println("Garbage collected from boject" + i); i++; } }
Example Program for GC OutOfMemoryError
垃圾回收機(jī)制并不保證發(fā)生內(nèi)存溢出時的安全,事實(shí)上內(nèi)存溢出將會導(dǎo)致程序的崩潰,拋出OutOfMemoryError。
import java.util.LinkedList; import java.util.List; public class GC { public static void main(String[] args[]) { List l = new LinkedList(); //進(jìn)入內(nèi)部無限循環(huán)直接向鏈表中不斷添加元素 do { l.add(new String("Hello, World!"); } while (true); } }
Output
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)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65042.html
摘要:垃圾回收監(jiān)控和分析工具是在安裝時免費(fèi)提供的。監(jiān)控現(xiàn)在可以監(jiān)控垃圾回收過程了。至少我們可以知道程序中存在和對象內(nèi)存分配和垃圾回收相關(guān)的問題。到此為止,關(guān)于垃圾回收的系列文章已經(jīng)完結(jié)了。 本文非原創(chuàng),翻譯自Java Garbage Collection Monitoring and Analysis在Java中為對象分配和釋放內(nèi)存空間都是由垃圾回收線程自動執(zhí)行完成的。和C語言不一樣的是Ja...
摘要:在架構(gòu)中,堆內(nèi)存和垃圾回收器這兩個部分和垃圾回收相關(guān)。堆內(nèi)存在的內(nèi)存模型中,最重要的是要了解堆內(nèi)存的概念。在垃圾回收的過程中,這些對象將被從堆內(nèi)存中清除,同時它們的空間也就被回收了。 本文非原創(chuàng),翻譯自Java Garbage Collection introduction在Java中為對象分配和釋放內(nèi)存空間都是由垃圾回收線程自動執(zhí)行完成的。和C語言不一樣的是Java程序員不需要手動寫...
摘要:并發(fā)標(biāo)記清除垃圾回收器,使用多個線程來掃描堆內(nèi)存并標(biāo)記可被清除的對象,然后清除標(biāo)記的對象。垃圾回收器應(yīng)用于大的堆內(nèi)存空間。它將堆內(nèi)存空間劃分為不同的區(qū)域,對各個區(qū)域并行地做回收工作。它會通過把重復(fù)的值移動到同一個數(shù)組來優(yōu)化堆內(nèi)存占用。 本文非原創(chuàng),翻譯自Types of Java Garbage Collectors在Java中為對象分配和釋放內(nèi)存空間都是由垃圾回收線程自動執(zhí)行完成的。...
摘要:執(zhí)行引擎作用執(zhí)行字節(jié)碼,或者執(zhí)行本地方法運(yùn)行時數(shù)據(jù)區(qū)其實(shí)就是指在運(yùn)行期間,其對內(nèi)存空間的劃分和分配。 雖是讀書筆記,但是如轉(zhuǎn)載請注明出處https://uestc-dpz.github.io..拒絕伸手復(fù)制黨 JVM Java 虛擬機(jī) Java 虛擬機(jī)(Java virtual machine,JVM)是運(yùn)行 Java 程序必不可少的機(jī)制。JVM實(shí)現(xiàn)了Java語言最重要的特征:即平臺...
摘要:要加左右,因?yàn)槲粰C(jī)器上的對象更大要加左右,因?yàn)槲粰C(jī)器上的對象更大對于服務(wù)器程序的原則是保證越多內(nèi)存越好將和設(shè)置成一樣大,關(guān)掉自動調(diào)整大小的機(jī)制。對于服務(wù)器程序的原則是決定你能夠給的最大內(nèi)存,然后根據(jù)的大小來找到最好的設(shè)置。 Generations Young Generation 組成:eden + 2 survivor spaces Young generation的gc稱作min...
閱讀 986·2021-11-24 09:39
閱讀 2205·2021-11-16 11:54
閱讀 2084·2021-11-11 17:22
閱讀 2376·2021-09-30 09:55
閱讀 3598·2021-08-12 13:22
閱讀 1629·2019-08-30 15:44
閱讀 1174·2019-08-29 12:12
閱讀 3268·2019-08-27 10:58