強(qiáng)引用、軟引用、弱引用、虛引用是什么,有什么區(qū)別?
強(qiáng)引用:在程序中普遍存在的引用賦值,類似Object obj = new Object()這種引用關(guān)系。只要強(qiáng)引用關(guān)系還存在,垃圾收集器就永遠(yuǎn)不會(huì)回收掉被引用的對象。
軟引用:如果內(nèi)存空間足夠,垃圾回收器就不會(huì)回收它,如果內(nèi)存空間不足了,就會(huì)回收這些對象的內(nèi)存。
//軟引用
SoftReference<String> softRef = new SoftReference<String>(str);
弱引用:在進(jìn)行垃圾回收時(shí),不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收只具有弱引用的對象。
//弱引用
WeakReference<String> weakRef = new WeakReference<String>(str);
虛引用:虛引用并不會(huì)決定對象的生命周期。如果一個(gè)對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收。虛引用主要是為了能在對象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。
Minor GC 和 Full GC的區(qū)別?
Minor GC:回收新生代,因?yàn)樾律鷮ο蟠婊顣r(shí)間很短,因此Minor GC會(huì)頻繁執(zhí)行,執(zhí)行的速度一般也會(huì)比較快。
Full GC:回收老年代和新生代,老年代的對象存活時(shí)間長,因此Full GC很少執(zhí)行,執(zhí)行速度會(huì)比Minor GC慢很多。
內(nèi)存的分配策略?
對象優(yōu)先在 Eden 分配
大多數(shù)情況下,對象在新生代Eden上分配,當(dāng)Eden空間不夠時(shí),觸發(fā)Minor GC。
大對象直接進(jìn)入老年代
大對象是指需要連續(xù)內(nèi)存空間的對象,最典型的大對象有長字符串和大數(shù)組??梢栽O(shè)置JVM參數(shù)-XX:PretenureSizeThreshold,大于此值的對象直接在老年代分配。
長期存活的對象進(jìn)入老年代
通過參數(shù)-XX:MaxTenuringThreshold可以設(shè)置對象進(jìn)入老年代的年齡閾值。對象在Survivor區(qū)每經(jīng)過一次Minor GC,年齡就增加 1 歲,當(dāng)它的年齡增加到一定程度,就會(huì)被晉升到老年代中。
動(dòng)態(tài)對象年齡判定
并非對象的年齡必須達(dá)到MaxTenuringThreshold才能晉升老年代,如果在Survivor中相同年齡所有對象大小的總和大于Survivor空間的一半,則年齡大于或等于該年齡的對象可以直接進(jìn)入老年代,無需達(dá)到MaxTenuringThreshold年齡閾值。
空間分配擔(dān)保
在發(fā)生Minor GC之前,虛擬機(jī)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象總空間,如果條件成立的話,那么Minor GC是安全的。如果不成立的話虛擬機(jī)會(huì)查看HandlePromotionFailure的值是否允許擔(dān)保失敗。如果允許,那么就會(huì)繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小,如果大于,將嘗試著進(jìn)行一次Minor GC;如果小于,或者HandlePromotionFailure的值為不允許擔(dān)保失敗,那么就要進(jìn)行一次Full GC。
Full GC 的觸發(fā)條件?
????????對于 Minor GC,其觸發(fā)條件比較簡單,當(dāng) Eden 空間滿時(shí),就將觸發(fā)一次 Minor GC。而 Full GC 觸發(fā)條件相對復(fù)雜,有以下情況會(huì)發(fā)生 full GC:
調(diào)用 System.gc()
????????只是建議虛擬機(jī)執(zhí)行 Full GC,但是虛擬機(jī)不一定真正去執(zhí)行。不建議使用這種方式,而是讓虛擬機(jī)管理內(nèi)存。
老年代空間不足
????????老年代空間不足的常見場景為前文所講的大對象直接進(jìn)入老年代、長期存活的對象進(jìn)入老年代等。為了避免以上原因引起的 Full GC,應(yīng)當(dāng)盡量不要?jiǎng)?chuàng)建過大的對象以及數(shù)組。除此之外,可以通過 -Xmn 參數(shù)調(diào)大新生代的大小,讓對象盡量在新生代被回收掉,不進(jìn)入老年代。還可以通過 -XX:MaxTenuringThreshold 調(diào)大對象進(jìn)入老年代的年齡,讓對象在新生代多存活一段時(shí)間。
空間分配擔(dān)保失敗
????????使用復(fù)制算法的 Minor GC 需要老年代的內(nèi)存空間作擔(dān)保,如果擔(dān)保失敗會(huì)執(zhí)行一次 Full GC。
JDK 1.7 及以前的永久代空間不足
????????在 JDK 1.7 及以前,HotSpot 虛擬機(jī)中的方法區(qū)是用永久代實(shí)現(xiàn)的,永久代中存放的為一些 Class 的信息、常量、靜態(tài)變量等數(shù)據(jù)。當(dāng)系統(tǒng)中要加載的類、反射的類和調(diào)用的方法較多時(shí),永久代可能會(huì)被占滿,在未配置為采用 CMS GC 的情況下也會(huì)執(zhí)行 Full GC。如果經(jīng)過 Full GC 仍然回收不了,那么虛擬機(jī)會(huì)拋出 java.lang.OutOfMemoryError。
垃圾回收算法有哪些?
垃圾回收算法有四種,分別是標(biāo)記清除法、標(biāo)記整理法、復(fù)制算法、分代收集算法。
標(biāo)記清除算法
首先利用可達(dá)性去遍歷內(nèi)存,把存活對象和垃圾對象進(jìn)行標(biāo)記。標(biāo)記結(jié)束后統(tǒng)一將所有標(biāo)記的對象回收掉。這種垃圾回收算法效率較低,并且會(huì)產(chǎn)生大量不連續(xù)的空間碎片。

復(fù)制清除算法
????????半?yún)^(qū)復(fù)制,用于新生代垃圾回收。將內(nèi)存分為大小相同的兩塊,每次使用其中的一塊。當(dāng)這一塊的內(nèi)存使用完后,就將還存活的對象復(fù)制到另一塊去,然后再把使用的空間一次清理掉。
特點(diǎn):實(shí)現(xiàn)簡單,運(yùn)行高效,但可用內(nèi)存縮小為了原來的一半,浪費(fèi)空間。
標(biāo)記整理算法
根據(jù)老年代的特點(diǎn)提出的一種標(biāo)記算法,標(biāo)記過程仍然與標(biāo)記-清除算法一樣,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理,而是讓所有存活的對象都向一端移動(dòng),然后直接清理掉邊界以外的內(nèi)存。

分類收集算法
根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴?。一般將堆分為新生代和老年代?/p>
新生代使用復(fù)制算法
老年代使用標(biāo)記清除算法或者標(biāo)記整理算法
????????在新生代中,每次垃圾收集時(shí)都有大批對象死去,只有少量存活,使用復(fù)制算法比較合適,只需要付出少量存活對象的復(fù)制成本就可以完成收集。老年代對象存活率高,適合使用標(biāo)記-清理或者標(biāo)記-整理算法進(jìn)行垃圾回收。
有哪些垃圾回收器?
垃圾回收器主要分為以下幾種:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1。
這7種垃圾收集器的特點(diǎn):

Serial 收集器
????????單線程收集器,使用一個(gè)垃圾收集線程去進(jìn)行垃圾回收,在進(jìn)行垃圾回收的時(shí)候必須暫停其他所有的工作線程(Stop The World),直到它收集結(jié)束。
????????特點(diǎn):簡單高效;內(nèi)存消耗?。粵]有線程交互的開銷,單線程收集效率高;需暫停所有的工作線程,用戶體驗(yàn)不好。
ParNew 收集器
????????Serial收集器的多線程版本,除了使用多線程進(jìn)行垃圾收集外,其他行為、參數(shù)與Serial收集器基本一致。
Parallel Scavenge 收集器
????????新生代收集器,基于復(fù)制清除算法實(shí)現(xiàn)的收集器。特點(diǎn)是吞吐量優(yōu)先,能夠并行收集的多線程收集器,允許多個(gè)垃圾回收線程同時(shí)運(yùn)行,降低垃圾收集時(shí)間,提高吞吐量。所謂吞吐量就是 CPU 中用于運(yùn)行用戶代碼的時(shí)間與 CPU 總消耗時(shí)間的比值(吞吐量 = 運(yùn)行用戶代碼時(shí)間 /(運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間))。Parallel Scavenge收集器關(guān)注點(diǎn)是吞吐量,高效率的利用 CPU 資源。CMS垃圾收集器關(guān)注點(diǎn)更多的是用戶線程的停頓時(shí)間。
????????Parallel Scavenge收集器提供了兩個(gè)參數(shù)用于精確控制吞吐量,分別是控制最大垃圾收集停頓時(shí)間的-XX:MaxGCPauseMillis參數(shù)以及直接設(shè)置吞吐量大小的-XX:GCTimeRatio參數(shù)。
-XX:MaxGCPauseMillis參數(shù)的值是一個(gè)大于0的毫秒數(shù),收集器將盡量保證內(nèi)存回收花費(fèi)的時(shí)間不超過用戶設(shè)定值。
-XX:GCTimeRatio參數(shù)的值大于0小于100,即垃圾收集時(shí)間占總時(shí)間的比率,相當(dāng)于吞吐量的倒數(shù)。
Serial Old 收集器
????Serial收集器的老年代版本,單線程收集器,使用標(biāo)記整理算法。
Parallel Old 收集器
????Parallel Scavenge收集器的老年代版本。多線程垃圾收集,使用標(biāo)記整理算法。
CMS 收集器
????Concurrent Mark Sweep,并發(fā)標(biāo)記清除,追求獲取最短停頓時(shí)間,實(shí)現(xiàn)了讓垃圾收集線程與用戶線程基本上同時(shí)工作。
CMS垃圾回收基于標(biāo)記清除算法實(shí)現(xiàn),整個(gè)過程分為四個(gè)步驟:
初始標(biāo)記: 暫停所有用戶線程(Stop The World),記錄直接與GC Roots直接相連的對象 。
并發(fā)標(biāo)記:從GC Roots開始對堆中對象進(jìn)行可達(dá)性分析,找出存活對象,耗時(shí)較長,但是不需要停頓用戶線程。
重新標(biāo)記: 在并發(fā)標(biāo)記期間對象的引用關(guān)系可能會(huì)變化,需要重新進(jìn)行標(biāo)記。此階段也會(huì)暫停所有用戶線程。
并發(fā)清除:清除標(biāo)記對象,這個(gè)階段也是可以與用戶線程同時(shí)并發(fā)的。
在整個(gè)過程中,耗時(shí)最長的是并發(fā)標(biāo)記和并發(fā)清除階段,這兩個(gè)階段垃圾收集線程都可以與用戶線程一起工作,所以從總體上來說,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。
優(yōu)點(diǎn):并發(fā)收集,停頓時(shí)間短。
缺點(diǎn):
標(biāo)記清除算法導(dǎo)致收集結(jié)束有大量空間碎片。
產(chǎn)生浮動(dòng)垃圾,在并發(fā)清理階段用戶線程還在運(yùn)行,會(huì)不斷有新的垃圾產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法在當(dāng)次收集中回收它們,只好等到下一次垃圾回收再處理;
G1收集器
G1垃圾收集器的目標(biāo)是在不同應(yīng)用場景中追求高吞吐量和低停頓之間的最佳平衡。
G1將整個(gè)堆分成相同大小的分區(qū)(Region),有四種不同類型的分區(qū):Eden、Survivor、Old和Humongous。分區(qū)的大小取值范圍為 1M 到 32M,都是2的冪次方。分區(qū)大小可以通過-XX:G1HeapRegionSize參數(shù)指定。Humongous區(qū)域用于存儲(chǔ)大對象。G1規(guī)定只要大小超過了一個(gè)分區(qū)容量一半的對象就認(rèn)為是大對象。

?G1 收集器對各個(gè)分區(qū)回收所獲得的空間大小和回收所需時(shí)間的經(jīng)驗(yàn)值進(jìn)行排序,得到一個(gè)優(yōu)先級(jí)列表,每次根據(jù)用戶設(shè)置的最大回收停頓時(shí)間,優(yōu)先回收價(jià)值最大的分區(qū)。
特點(diǎn):可以由用戶指定期望的垃圾收集停頓時(shí)間。
G1 收集器的回收過程分為以下幾個(gè)步驟:
初始標(biāo)記。暫停所有其他線程,記錄直接與GC Roots直接相連的對象,耗時(shí)較短 。
并發(fā)標(biāo)記。從GC Roots開始對堆中對象進(jìn)行可達(dá)性分析,找出要回收的對象,耗時(shí)較長,不過可以和用戶程序并發(fā)執(zhí)行。
最終標(biāo)記。需對其他線程做短暫的暫停,用于處理并發(fā)標(biāo)記階段對象引用出現(xiàn)變動(dòng)的區(qū)域。
篩選回收。對各個(gè)分區(qū)的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的停頓時(shí)間來制定回收計(jì)劃,然后把決定回收的分區(qū)的存活對象復(fù)制到空的分區(qū)中,再清理掉整個(gè)舊的分區(qū)的全部空間。這里的操作涉及存活對象的移動(dòng),會(huì)暫停用戶線程,由多條收集器線程并行完成。
Java學(xué)習(xí)視頻
Java基礎(chǔ):Java300集,Java必備優(yōu)質(zhì)視頻_手把手圖解學(xué)習(xí)Java,讓學(xué)習(xí)成為一種享受