Java垃圾回收機(jī)制

一、垃圾回收機(jī)制的意義
Java語言中一個(gè)顯著的特點(diǎn)就是引入了垃圾回收機(jī)制,使c++程序員最頭疼的內(nèi)存管理的問題迎刃而解,它使得Java程序員在編寫程序的時(shí)候不再需要考慮內(nèi)存管理。由于有個(gè)垃圾回收機(jī)制,Java中的對(duì)象不再有“作用域”的概念,只有對(duì)象的引用才有“作用域”。垃圾回收可以有效的防止內(nèi)存泄露,有效的使用空閑的內(nèi)存。
ps:內(nèi)存泄露是指該內(nèi)存空間使用完畢之后未回收,在不涉及復(fù)雜數(shù)據(jù)結(jié)構(gòu)的一般情況下,Java 的內(nèi)存泄露表現(xiàn)為一個(gè)內(nèi)存對(duì)象的生命周期超出了程序需要它的時(shí)間長度,我們有時(shí)也將其稱為“對(duì)象游離”。

二:垃圾回收機(jī)制的算法
Java語言規(guī)范沒有明確的說明JVM 使用哪種垃圾回收算法,但是任何一種垃圾回收算法一般要做兩件基本事情:
(1)發(fā)現(xiàn)無用的信息對(duì)象;(2)回收將無用對(duì)象占用的內(nèi)存空間。使該空間可被程序再次使用。
1:算法分析:
1.1.引用計(jì)數(shù)法(Reference Counting Collector)
也就是說當(dāng)使用了創(chuàng)建好的對(duì)象的時(shí)候?qū)ο髮?shí)例的引用計(jì)數(shù)器+1;當(dāng)超過了生命周期或者設(shè)置了新值的時(shí)候?qū)嵗囊糜?jì)數(shù)器-1
引用計(jì)數(shù)算法是垃圾回收器中的早起策略,在這種方法中,堆中的每個(gè)對(duì)象實(shí)例都有一個(gè)引用計(jì)數(shù)器,點(diǎn)一個(gè)對(duì)象被創(chuàng)建時(shí),且該對(duì)象實(shí)例分配給一個(gè)變量,該變量計(jì)數(shù)設(shè)置為1 ,當(dāng)任何其他變量賦值為這個(gè)對(duì)象的引用時(shí),計(jì)數(shù)加1 ,(a=b ,則b引用的對(duì)象實(shí)例計(jì)數(shù)器+1)但當(dāng)一個(gè)對(duì)象實(shí)例的某個(gè)引用超過了生命周期或者被設(shè)置為一個(gè)新值時(shí),對(duì)象實(shí)例的引用計(jì)數(shù)器減1,任何引用計(jì)數(shù)器為0 的對(duì)象實(shí)例可以當(dāng)做垃圾收集。 當(dāng)一個(gè)對(duì)象的實(shí)例被垃圾收集是,它引用的任何對(duì)象實(shí)例的引用計(jì)數(shù)器減1.
1.2優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
引用計(jì)數(shù)收集器可以很快的執(zhí)行,交織在程序運(yùn)行中。對(duì)程序需要不被長時(shí)間打斷的實(shí)時(shí)環(huán)境比較有利。
缺點(diǎn):
無法檢測出循環(huán)引用。如父對(duì)象有一個(gè)對(duì)子對(duì)象的引用,子對(duì)象反過來引用父對(duì)象。這樣,他們的引用計(jì)數(shù)永遠(yuǎn)不可能為0.

2. compacting算法(Compacting Collector)

為了解決堆碎片問題,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的過程中,算法將所有的對(duì)象移到堆的一端,堆的另一端就變成了一個(gè)相鄰的空閑內(nèi)存區(qū),收集器會(huì)對(duì)它移動(dòng)的所有對(duì)象的所有引用進(jìn)行更新,使得這些引用在新的位置能識(shí)別原來的對(duì)象。在基于Compacting算法的收集器的實(shí)現(xiàn)中,一般增加句柄和句柄表。

3 copying算法(Coping Collector)
  該算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時(shí)把堆分成一個(gè)對(duì)象區(qū)和多個(gè)空閑區(qū),程序從對(duì)象區(qū)為對(duì)象分配空間,當(dāng)對(duì)象滿了,基于coping算法的垃圾回收就從根集中掃描活動(dòng)對(duì)象,并將每個(gè)活動(dòng)對(duì)象復(fù)制到空閑區(qū)(使得活動(dòng)對(duì)象所占的內(nèi)存之間沒有空閑間隔),這樣空閑區(qū)變成了對(duì)象區(qū),原來的對(duì)象區(qū)變成了空閑區(qū),程序會(huì)在新的對(duì)象區(qū)中分配內(nèi)存。
  一種典型的基于coping算法的垃圾回收是stop-and-copy算法,它將堆分成對(duì)象區(qū)和空閑區(qū)域區(qū),在對(duì)象區(qū)與空閑區(qū)域的切換過程中,程序暫停執(zhí)行。

4 generation算法(Generational Collector)
  stop-and-copy垃圾收集器的一個(gè)缺陷是收集器必須復(fù)制所有的活動(dòng)對(duì)象,這增加了程序等待時(shí)間,這是coping算法低效的原因。在程序設(shè)計(jì)中有這樣的規(guī)律:多數(shù)對(duì)象存在的時(shí)間比較短,少數(shù)的存在時(shí)間比較長。因此,generation算法將堆分成兩個(gè)或多個(gè),每個(gè)子堆作為對(duì)象的一代 (generation)。由于多數(shù)對(duì)象存在的時(shí)間比較短,隨著程序丟棄不使用的對(duì)象,垃圾收集器將從最年輕的子堆中收集這些對(duì)象。在分代式的垃圾收集器運(yùn)行后,上次運(yùn)行存活下來的對(duì)象移到下一最高代的子堆中,由于老一代的子堆不會(huì)經(jīng)常被回收,因而節(jié)省了時(shí)間。

5adaptive算法(Adaptive Collector)
  在特定的情況下,一些垃圾收集算法會(huì)優(yōu)于其它算法?;贏daptive算法的垃圾收集器就是監(jiān)控當(dāng)前堆的使用情況,并將選擇適當(dāng)算法的垃圾收集器。

三.System.gc()方法
  使用System.gc()可以不管JVM使用的是哪一種垃圾回收的算法,都可以請(qǐng)求Java的垃圾回收。在命令行中有一個(gè)參數(shù)-verbosegc可以查看Java使用的堆內(nèi)存的情況,它的格式如下:java -verbosegc classfile 由于這種方法會(huì)影響系統(tǒng)性能,不推薦使用,所以不詳訴.
需要注意的是,調(diào)用System.gc()也僅僅是一個(gè)請(qǐng)求(建議)。JVM接受這個(gè)消息后,并不是立即做垃圾回收,而只是對(duì)幾個(gè)垃圾回收算法做了加權(quán),使垃圾回收操作容易發(fā)生,或提早發(fā)生,或回收較多而已。

四. finalize()方法
  在JVM垃圾回收器收集一個(gè)對(duì)象之前,一般要求程序調(diào)用適當(dāng)?shù)姆椒ㄡ尫刨Y源,但在沒有明確釋放資源的情況下,Java提供了缺省機(jī)制來終止該對(duì)象心釋放資源,這個(gè)方法就是finalize()。它的原型為:protected void finalize() throws Throwable 在finalize()方法返回之后,對(duì)象消失,垃圾收集開始執(zhí)行。原型中的throws Throwable表示它可以拋出任何類型的異常。
  之所以要使用finalize(),是存在著垃圾回收器不能處理的特殊情況。例如:1)由于在分配內(nèi)存的時(shí)候可能采用了類似 C語言的做法,而非JAVA的通常new做法。這種情況主要發(fā)生在native method中,比如native method調(diào)用了C/C++方法malloc()函數(shù)系列來分配存儲(chǔ)空間,但是除非調(diào)用free()函數(shù),否則這些內(nèi)存空間將不會(huì)得到釋放,那么這個(gè)時(shí)候就可能造成內(nèi)存泄漏。但是由于free()方法是在C/C++中的函數(shù),所以finalize()中可以用本地方法來調(diào)用它。以釋放這些“特殊” 的內(nèi)存空間。2)又或者打開的文件資源,這些資源不屬于垃圾回收器的回收范圍。
只有到下一次再進(jìn)行垃圾回收動(dòng)作的時(shí)候,才會(huì)真正釋放這個(gè)對(duì)象所占用的內(nèi)存空間。


五.Java堆內(nèi)存的分代管理
Java垃圾回收是需要消耗CPU和內(nèi)存資源的,其速度隨著內(nèi)存的變大而減慢,這將嚴(yán)重影響系統(tǒng)的性能。同時(shí),Java系統(tǒng)中存在著這么一種現(xiàn)象:大多數(shù)Java對(duì)象都是“短命”的?;诖?,Java采用了分代的內(nèi)存管理方式,并在不同的內(nèi)存代中采用不同的垃圾回收算法,從而達(dá)到對(duì)內(nèi)存更細(xì)粒度的管理,最大限度地減小垃圾回收對(duì)系統(tǒng)本身的影響。


image.png
 由上圖所示,Java的堆空間被分為了三個(gè)區(qū)域,分別是新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)。新創(chuàng)建出來的對(duì)象首先存放在新生代,經(jīng)過新生代中多次垃圾回收(在Survivor 0和Survivor 1之間來回復(fù)制),存活下來的對(duì)象將被轉(zhuǎn)移到老年代。新生代中垃圾回收很頻繁,這樣多數(shù)“短命”的對(duì)象將得到及時(shí)清理;又由于新生代內(nèi)存空間通常不大,回收速度也相對(duì)較快。在老年代中,存放著從新生代中經(jīng)歷了多次垃圾回收后仍然存活的對(duì)象,這些對(duì)象相對(duì)較少,而老年代內(nèi)存一般很大,并不容易塞滿,因此老年代的垃圾回收頻率要遠(yuǎn)遠(yuǎn)低于新生代,從而減少了對(duì)系統(tǒng)性能的影響。永久代中主要存放Java類本身的數(shù)據(jù)信息,當(dāng)Java類不再被使用時(shí),也會(huì)被垃圾回收掉。開發(fā)者們通常無法預(yù)測永久代的大小,導(dǎo)致程序經(jīng)常出現(xiàn) “java.lang.OutOfMemoryError: Permgen space”錯(cuò)誤,因此在Java 8中,使用jvm進(jìn)程原生內(nèi)存空間的Metaspace代替了永久代。在默認(rèn)情況下,Metaspace將使用jvm進(jìn)程所有可用的內(nèi)存。
  在新生代進(jìn)行的GC叫做minor GC,在老年代進(jìn)行的GC都叫major GC,F(xiàn)ull GC同時(shí)作用于新生代和老年代。在垃圾回收過程中經(jīng)常涉及到對(duì)對(duì)象的挪動(dòng)(比如上文提到的對(duì)象在Survivor 0和Survivor 1之間的復(fù)制),進(jìn)而導(dǎo)致需要對(duì)對(duì)象引用進(jìn)行更新。為了保證引用更新的正確性,Java將暫停所有其他的線程,這種情況被稱為“Stop-The-World”,導(dǎo)致系統(tǒng)全局停頓。Stop-The-World對(duì)系統(tǒng)性能存在影響,因此垃圾回收的一個(gè)原則是盡量減少“Stop-The-World”的時(shí)間。

六.垃圾收集器:
在Java中主要有4種垃圾收集器,他們各自對(duì)于不同的內(nèi)存代采用不同的算法。Java會(huì)根據(jù)當(dāng)前系統(tǒng)的基本配置確定一個(gè)默認(rèn)的垃圾收集器,你可以通過以下命令查看:
java -XX:+PrintCommandLineFlags -version
電腦上會(huì)輸出:
-XX:InitialHeapSize=132189120 -XX:MaxHeapSize=2115025920 -XX:+PrintCommandLineFlags -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
由紅色部分可以看出,默認(rèn)情況下使用了Parallel收集器,這也是多數(shù)Java機(jī)器(特別是服務(wù)器)默認(rèn)的垃圾收集器。

6.1串行收集器(Serial Collector)
顧名思義,串行收集器指采用單線程進(jìn)行垃圾回收,回收時(shí)會(huì)導(dǎo)致長時(shí)間的Stop-The-World,主要用于單機(jī)程序。該收集器在新生代采用復(fù)制算法,在老年代采用標(biāo)記-壓縮算法??梢酝ㄟ^-XX:+UseSerialGC命令行選項(xiàng)激活該收集器。

6.2并行收集器(Parallel Collector)
該收集器同樣在新生代采用復(fù)制算法,在老年代采用標(biāo)記-壓縮算法,只是使用了多線程的方式進(jìn)行垃圾回收,從而大大提高了回收效率,但是回收過程中同時(shí)需要Stop-The-World??梢酝ㄟ^-XX:+UseParallelGC激活該收集器。多數(shù)情況下,并行收集器是Java的默認(rèn)收集器。

6.3并發(fā)標(biāo)記清除收集器(Concurrent Mark Sweep Collector,CMS)
該收集器在在新生代中采用復(fù)制算法,在老年代采用標(biāo)記-清除算法(不是標(biāo)記-壓縮)。之所以叫“并發(fā)”,是因?yàn)樵诨厥者^程的某些階段,回收線程和用戶線程同時(shí)執(zhí)行,當(dāng)然不是整個(gè)回收過程都可以和用戶線程并行的,該收集器也存在Stop-The-World的時(shí)候,只是相比于其他收集器來說Stop-The-World持續(xù)時(shí)間較少而已??梢酝ㄟ^-XX:+UseConcMarkSweepGC激活該收集器。

6.4G1收集器(Garbage First Collector)
G1收集器是Java世界最新的收集器,在Java 9中,它將成為默認(rèn)的垃圾收集器。該收集器采用與上文中提到的收集器不同方式來對(duì)待Java對(duì)內(nèi)存,如下圖所示。可以通過-XX:+UseG1GC激活該收集器。


image.png

七.觸發(fā)主GC(Garbage Collector)的條件
  JVM進(jìn)行次GC的頻率很高,但因?yàn)檫@種GC占用時(shí)間極短,所以對(duì)系統(tǒng)產(chǎn)生的影響不大。更值得關(guān)注的是主GC的觸發(fā)條件,因?yàn)樗鼘?duì)系統(tǒng)影響很明顯。總的來說,有兩個(gè)條件會(huì)觸發(fā)主GC:
  1)當(dāng)應(yīng)用程序空閑時(shí),即沒有應(yīng)用線程在運(yùn)行時(shí),GC會(huì)被調(diào)用。因?yàn)镚C在優(yōu)先級(jí)最低的線程中進(jìn)行,所以當(dāng)應(yīng)用忙時(shí),GC線程就不會(huì)被調(diào)用,但以下條件除外。
  2)Java堆內(nèi)存不足時(shí),GC會(huì)被調(diào)用。當(dāng)應(yīng)用線程在運(yùn)行,并在運(yùn)行過程中創(chuàng)建新對(duì)象,若這時(shí)內(nèi)存空間不足,JVM就會(huì)強(qiáng)制地調(diào)用GC線程,以便回收內(nèi)存用于新的分配。若GC一次之后仍不能滿足內(nèi)存分配的要求,JVM會(huì)再進(jìn)行兩次GC作進(jìn)一步的嘗試,若仍無法滿足要求,則 JVM將報(bào)“out of memory”的錯(cuò)誤,Java應(yīng)用將停止。
  由于是否進(jìn)行主GC由JVM根據(jù)系統(tǒng)環(huán)境決定,而系統(tǒng)環(huán)境在不斷的變化當(dāng)中,所以主GC的運(yùn)行具有不確定性,無法預(yù)計(jì)它何時(shí)必然出現(xiàn),但可以確定的是對(duì)一個(gè)長期運(yùn)行的應(yīng)用來說,其主GC是反復(fù)進(jìn)行的。

八. 減少GC開銷的措施
  根據(jù)上述GC的機(jī)制,程序的運(yùn)行會(huì)直接影響系統(tǒng)環(huán)境的變化,從而影響GC的觸發(fā)。若不針對(duì)GC的特點(diǎn)進(jìn)行設(shè)計(jì)和編碼,就會(huì)出現(xiàn)內(nèi)存駐留等一系列負(fù)面影響。為了避免這些影響,基本的原則就是盡可能地減少垃圾和減少GC過程中的開銷。具體措施包括以下幾個(gè)方面:
  (1)不要顯式調(diào)用System.gc()
  此函數(shù)建議JVM進(jìn)行主GC,雖然只是建議而非一定,但很多情況下它會(huì)觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)。
  (2)盡量減少臨時(shí)對(duì)象的使用
  臨時(shí)對(duì)象在跳出函數(shù)調(diào)用后,會(huì)成為垃圾,少用臨時(shí)變量就相當(dāng)于減少了垃圾的產(chǎn)生,從而延長了出現(xiàn)上述第二個(gè)觸發(fā)條件出現(xiàn)的時(shí)間,減少了主GC的機(jī)會(huì)。
  (3)對(duì)象不用時(shí)最好顯式置為Null
  一般而言,為Null的對(duì)象都會(huì)被作為垃圾處理,所以將不用的對(duì)象顯式地設(shè)為Null,有利于GC收集器判定垃圾,從而提高了GC的效率。
  (4)盡量使用StringBuffer,而不用String來累加字符串
  由于String是固定長的字符串對(duì)象,累加String對(duì)象時(shí),并非在一個(gè)String對(duì)象中擴(kuò)增,而是重新創(chuàng)建新的String對(duì)象,如Str5=Str1+Str2+Str3+Str4,這條語句執(zhí)行過程中會(huì)產(chǎn)生多個(gè)垃圾對(duì)象,因?yàn)閷?duì)次作“+”操作時(shí)都必須創(chuàng)建新的String對(duì)象,但這些過渡對(duì)象對(duì)系統(tǒng)來說是沒有實(shí)際意義的,只會(huì)增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字符串,因StringBuffer是可變長的,它在原有基礎(chǔ)上進(jìn)行擴(kuò)增,不會(huì)產(chǎn)生中間對(duì)象。
  (5)能用基本類型如Int,Long,就不用Integer,Long對(duì)象
  基本類型變量占用的內(nèi)存資源比相應(yīng)對(duì)象占用的少得多,如果沒有必要,最好使用基本變量。
  (6)盡量少用靜態(tài)對(duì)象變量
  靜態(tài)變量屬于全局變量,不會(huì)被GC回收,它們會(huì)一直占用內(nèi)存。
  (7)分散對(duì)象創(chuàng)建或刪除的時(shí)間
  集中在短時(shí)間內(nèi)大量創(chuàng)建新對(duì)象,特別是大對(duì)象,會(huì)導(dǎo)致突然需要大量內(nèi)存,JVM在面臨這種情況時(shí),只能進(jìn)行主GC,以回收內(nèi)存或整合內(nèi)存碎片,從而增加主GC的頻率。集中刪除對(duì)象,道理也是一樣的。它使得突然出現(xiàn)了大量的垃圾對(duì)象,空閑空間必然減少,從而大大增加了下一次創(chuàng)建新對(duì)象時(shí)強(qiáng)制主GC的機(jī)會(huì)。

九. 關(guān)于垃圾回收的幾點(diǎn)補(bǔ)充
  經(jīng)過上述的說明,可以發(fā)現(xiàn)垃圾回收有以下的幾個(gè)特點(diǎn):
 ?。?)垃圾收集發(fā)生的不可預(yù)知性:由于實(shí)現(xiàn)了不同的垃圾回收算法和采用了不同的收集機(jī)制,所以它有可能是定時(shí)發(fā)生,有可能是當(dāng)出現(xiàn)系統(tǒng)空閑CPU資源時(shí)發(fā)生,也有可能是和原始的垃圾收集一樣,等到內(nèi)存消耗出現(xiàn)極限時(shí)發(fā)生,這與垃圾收集器的選擇和具體的設(shè)置都有關(guān)系。
 ?。?)垃圾收集的精確性:主要包括2 個(gè)方面:(a)垃圾收集器能夠精確標(biāo)記活著的對(duì)象;(b)垃圾收集器能夠精確地定位對(duì)象之間的引用關(guān)系。前者是完全地回收所有廢棄對(duì)象的前提,否則就可能造成內(nèi)存泄漏。而后者則是實(shí)現(xiàn)歸并和復(fù)制等算法的必要條件。所有不可達(dá)對(duì)象都能夠可靠地得到回收,所有對(duì)象都能夠重新分配,允許對(duì)象的復(fù)制和對(duì)象內(nèi)存的縮并,這樣就有效地防止內(nèi)存的支離破碎。
 ?。?)現(xiàn)在有許多種不同的垃圾收集器,每種有其算法且其表現(xiàn)各異,既有當(dāng)垃圾收集開始時(shí)就停止應(yīng)用程序的運(yùn)行,又有當(dāng)垃圾收集開始時(shí)也允許應(yīng)用程序的線程運(yùn)行,還有在同一時(shí)間垃圾收集多線程運(yùn)行。
 ?。?)垃圾收集的實(shí)現(xiàn)和具體的JVM 以及JVM的內(nèi)存模型有非常緊密的關(guān)系。不同的JVM 可能采用不同的垃圾收集,而JVM 的內(nèi)存模型決定著該JVM可以采用哪些類型垃圾收集?,F(xiàn)在,HotSpot 系列JVM中的內(nèi)存系統(tǒng)都采用先進(jìn)的面向?qū)ο蟮目蚣茉O(shè)計(jì),這使得該系列JVM都可以采用最先進(jìn)的垃圾收集。
 ?。?)隨著技術(shù)的發(fā)展,現(xiàn)代垃圾收集技術(shù)提供許多可選的垃圾收集器,而且在配置每種收集器的時(shí)候又可以設(shè)置不同的參數(shù),這就使得根據(jù)不同的應(yīng)用環(huán)境獲得最優(yōu)的應(yīng)用性能成為可能。
  針對(duì)以上特點(diǎn),我們?cè)谑褂玫臅r(shí)候要注意:
 ?。?)不要試圖去假定垃圾收集發(fā)生的時(shí)間,這一切都是未知的。比如,方法中的一個(gè)臨時(shí)對(duì)象在方法調(diào)用完畢后就變成了無用對(duì)象,這個(gè)時(shí)候它的內(nèi)存就可以被釋放。
 ?。?)Java中提供了一些和垃圾收集打交道的類,而且提供了一種強(qiáng)行執(zhí)行垃圾收集的方法--調(diào)用System.gc(),但這同樣是個(gè)不確定的方法。Java 中并不保證每次調(diào)用該方法就一定能夠啟動(dòng)垃圾收集,它只不過會(huì)向JVM發(fā)出這樣一個(gè)申請(qǐng),到底是否真正執(zhí)行垃圾收集,一切都是個(gè)未知數(shù)。
  (3)挑選適合自己的垃圾收集器。一般來說,如果系統(tǒng)沒有特殊和苛刻的性能要求,可以采用JVM的缺省選項(xiàng)。否則可以考慮使用有針對(duì)性的垃圾收集器,比如增量收集器就比較適合實(shí)時(shí)性要求較高的系統(tǒng)之中。系統(tǒng)具有較高的配置,有比較多的閑置資源,可以考慮使用并行標(biāo)記/清除收集器。
 ?。?)關(guān)鍵的也是難把握的問題是內(nèi)存泄漏。良好的編程習(xí)慣和嚴(yán)謹(jǐn)?shù)木幊虘B(tài)度永遠(yuǎn)是最重要的,不要讓自己的一個(gè)小錯(cuò)誤導(dǎo)致內(nèi)存出現(xiàn)大漏洞。
  (5)盡早釋放無用對(duì)象的引用。大多數(shù)程序員在使用臨時(shí)變量的時(shí)候,都是讓引用變量在退出活動(dòng)域(scope)后,自動(dòng)設(shè)置為null,暗示垃圾收集器來收集該對(duì)象,還必須注意該引用的對(duì)象是否被監(jiān)聽,如果有,則要去掉監(jiān)聽器,然后再賦空值。

* 在Java中,對(duì)象實(shí)例都是在堆上創(chuàng)建。一些類信息,常量,靜態(tài)變量等存儲(chǔ)在方法區(qū)。堆和方法區(qū)都是線程共享的。
* GC機(jī)制是由JVM提供,用來清理需要清除的對(duì)象,回收堆內(nèi)存。
* GC機(jī)制將Java程序員從內(nèi)存管理中解放了出來,可以更關(guān)注于業(yè)務(wù)邏輯。
* 在Java中,GC是由一個(gè)被稱為垃圾回收器的守護(hù)線程執(zhí)行的。
* 在從內(nèi)存回收一個(gè)對(duì)象之前會(huì)調(diào)用對(duì)象的finalize()方法。
* 作為一個(gè)Java開發(fā)者不能強(qiáng)制JVM執(zhí)行GC;GC的觸發(fā)由JVM依據(jù)堆內(nèi)存的大小來決定。
* System.gc()和Runtime.gc()會(huì)向JVM發(fā)送執(zhí)行GC的請(qǐng)求,但是JVM不保證一定會(huì)執(zhí)行GC。
* 如果堆沒有內(nèi)存創(chuàng)建新的對(duì)象了,會(huì)拋出OutOfMemoryError。

關(guān)于面試:

77、GC是什么? 為什么要有GC?   
GC是垃圾收集的意思(Gabage Collection),內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java提供的GC功能可以自動(dòng)監(jiān)測對(duì)象是否超過作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java語言沒有提供釋放已分配內(nèi)存的顯示操作方法。
78、垃圾回收的優(yōu)點(diǎn)和原理。并考慮2種回收機(jī)制。
Java語言中一個(gè)顯著的特點(diǎn)就是引入了垃圾回收機(jī)制,使c++程序員最頭疼的內(nèi)存管理的問題迎刃而解,它使得Java程序員在編寫程序的時(shí)候不再需要考慮內(nèi)存管理。由于有個(gè)垃圾回收機(jī)制,Java中的對(duì)象不再有"作用域"的概念,只有對(duì)象的引用才有"作用域"。垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個(gè)單獨(dú)的低級(jí)別的線程運(yùn)行,不可預(yù)知的情況下對(duì)內(nèi)存堆中已經(jīng)死亡的或者長時(shí)間沒有使用的對(duì)象進(jìn)行清除和回收,程序員不用實(shí)時(shí)的調(diào)用垃圾回收器對(duì)某個(gè)對(duì)象或所有對(duì)象進(jìn)行垃圾回收?;厥諜C(jī)制有分代復(fù)制垃圾回收和標(biāo)記垃圾回收,增量垃圾回收。

79、垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收內(nèi)存嗎?有什么辦法主動(dòng)通知虛擬機(jī)進(jìn)行垃圾回收?
對(duì)于GC來說,當(dāng)程序員創(chuàng)建對(duì)象時(shí),GC就開始監(jiān)控這個(gè)對(duì)象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對(duì)象。通過這種方式確定哪些對(duì)象是"可達(dá)的",哪些對(duì)象是"不可達(dá)的"。當(dāng)GC確定一些對(duì)象為"不可達(dá)"時(shí),GC就有責(zé)任回收這些內(nèi)存空間。可以。程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語言規(guī)范并不保證GC一定會(huì)執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容