垃圾回收的概念?
垃圾回收主要針對的是堆中的對象,堆是一個共享的區域,創建的對象和數組都放在這個位置。但是我們不能一直的創建對象,也不是所有的對象能一直存放,如果不進行垃圾回收,內存遲早會耗盡,及時的垃圾回收能提高內存的利用率以及存儲效率。
什么樣的對象進行垃圾回收?
如果一個或多個對象沒有任何的引用指向它了,那么這個對象現在就是垃圾,如果定位了垃圾,則有可能會被垃圾回收器回收。
如何定位垃圾?
引用計數法:一個對象被引用了一次,在當前對象頭上遞增一次引用次數,如果這個對象的引用次數為0,代表這個對象可以回收。
在創建對象時,對象對應的引用次數為1,如果后續給對象賦值NULL,則對象的引用次數會變為0,此時表明當前的對象是可以被垃圾回收的。
當對象間出現了循環引用時,引用計數法就會失效。會導致內存泄露
創建a和b之后,并且創建的對象之間有循環引用,則兩個對象的堆內存的ref初始值為2,在設置對象a和b為null后,由于循環引用的存在,內存區域的ref為1,導致這兩塊內存區域一直不能回收
可達性分析算法
現在的虛擬機采用的都是通過可達性分析算法來確定哪些內容是垃圾。
- Java虛擬機中的垃圾回收器采用可達性分析來探索所有存活的對象
- 可達性算法的流程:掃描堆中的對象,看是否能夠沿著GCRoot對象為起點的引用鏈找到該對象,找不到,表示可以回收
如上圖所示,由于從GC Roots開始沿著引用鏈進行尋找,并不能找到X?和 Y,因此X和Y可以回收
哪些對象可以作為GC Root呢?
1.虛擬機棧(棧幀中的本地變量表)中引用的對象
2.方法區中類靜態屬性引用的對象
3.方法區中常量引用的對象
4.本地方法棧中JNI(即一般說的Native方法)引用的對象
垃圾回收算法
JVM垃圾回收算法有哪些?
標記清除算法
將垃圾回收分為2個階段,分別是標記和清除。
1.根據可達性分析算法得出的垃圾進行標記
2.對這些標記為可回收的內容進行垃圾回收
標記清除算法的優缺點
優點:標記和清除的速度很快
缺點:碎片化較為嚴重,內存不連貫
復制算法
1.將內存劃分為兩個區域根據可達性分析算法得出的垃圾進行標記
2.將存活的對象復制到另一塊內存區域。然后清理邊界以外的垃圾
復制算法的優缺點
優點:在垃圾對象多的情況下,效率較高。清理后,內存無碎片。
缺點:分配的2塊內存空間,在同一時刻,只能使用1個,內存的使用率較低
標記整理算法
1.根據可達性分析算法得出的垃圾進行標記
2.對這些標記為可回收的內容進行垃圾回收
3.清除之后,將存活的對象進行整理,向一端移動,然后清理邊界意外的垃圾
優缺點同標記清除算法,解決了標記清除算法的碎片化的問題,同時,標記壓縮算法多了一步,對象移動內存位置的步驟,其效率也有有一定的影響。
JVM的分代回收
堆的區域劃分
在java8時,堆被分為了兩份:新生代和老年代【1:2]
對于新生代,內部又被分為了三個區域。
- 伊甸園區Eden,新生的對象都分配到這里
- 幸存者區survivor(分成from和to)
Eden區,from區,to區[8:1:1]
對象回收分代回收策略
- 新創建的對象,都會先分配到eden區
- 當伊甸園內存不足,標記伊甸園與from(現階段沒有)的存活對象
- 將存活對象采用復制算法復制到to中,復制完畢后,伊甸園和from內存都得到釋放
- 經過一段時間后伊甸園的內存又出現不足,標記eden區域to區存活的對象,將存活的對象復制from區
- 當幸存區對象熬過幾次回收(最多15次),晉升到老年代(幸存區內存不足或大對象會導致提前晉升)
MinorGC、Mixed GC、FulIGC的區別是什么?
MinorGC【youngGC】:發生在新生代的垃圾回收,暫停時間短(STW)
MixedGC:新生代+老年代部分區域的垃圾回收,G1收集器特有
FulIGC:新生代+老年代完整垃圾回收,暫停時間長(STW),應盡力避免
STW(Stop-The-World):暫停所有應用程序線程,等待垃圾回收的完戰
JVM中的垃圾回收器
在jvm中,實現了多種垃圾收集器,包括:
- 串行垃圾收集器:Serial GC、Serial Old GC
- 并行垃圾收集器:Parallel Old GC、ParNew GC
- CMS(并發)垃圾收集器:CMSGC,作用在老年代
- G1垃圾收集器,作用在新生代和老年代
串行垃圾回收器
- Serial和SerialOld串行垃圾收集器,是指使用單線程進行垃圾回收,堆內存較小,適合個人電腦
- Serial?作用于新生代,采用復制算法
- SerialOld?作用于老年代,采用標記-整理算法
- 垃圾回收時,只有一個線程在工作,并且java應用中的所有線程都要暫停(STW),等待垃圾回收的完成。
并行垃圾收集器
- ParallelNew和ParallelOld是一個并行垃圾回收器,JDK8默認使用此垃圾回收器
- ParallelNew 作用于新生代,采用復制算法
- ParallelOld 作用于老年代,采用標記-整理算法
- 垃圾回收時,多個線程在工作,并且java應用中的所有線程都要暫停(STW),等待垃圾回收的完成。
CMS(并發)垃圾收集器
CMS全稱ConcurrentMarkSweep,是一款并發的、使用標記-清除算法的垃圾回收器,該回收器是
針對老年代垃圾回收的,是一款以獲取最短回收停頓時間為目標的收集器,停頓時間短,用戶體驗
就好。其最大特點是在進行垃圾回收時,應用仍然能正常運行。
為什么要進行重新標記?
可能出現一種情況,當X一開始沒有在引用鏈上,但是在并發標記期間,某個對象對X引用,此時就不能對X進行回收,因此需要重新標記。
G1垃圾回收器
- 應用于新生代和老年代,在JDK9之后默認使用G1
- 劃分成多個區域,每個區域都可以充當eden,survivor,old,humongous,其中humongous專為大對象準備
- 采用復制算法
- 響應時間與吞吐量兼顧
- 分成三個階段:新生代回收(stw)、并發標記(重新標記stw)、混合收集
- 如果并發失敗(即回收速度趕不上創建新對象速度),會觸發FullGC
垃圾回收的流程
YoungCollection(年輕代垃圾回收)
1.初始時,所有區域都處于空閑狀態
2.創建了一些對象,挑出一些空閑區域作為伊甸園區存儲這些對象
3.當伊甸園需要垃圾回收時,挑出一個空閑區域作為幸存區,用復制算法復制存活對象,需要暫停用戶線程
在標記的過程中或者是在復制的過程中,都需要觸發STW
4.隨著時間流逝,伊甸園的內存又有不足,將伊甸園以及之前幸存區中的存活對象,采用復制算法,復制到新的幸存區,其中較老對象晉升至老年代
YoungCollection+ConcurrentMark(年輕代垃圾回收+并發標記)
5.當老年代占用內存超過閾值(默認是45%)后,觸發并發標記,在老年代中找到存活的對象,這時無需暫停用戶線程
6.并發標記之后,會有重新標記階段解決漏標問題,此時需要暫停用戶線程。
MixedCollection(混合垃圾回收)
混合收集階段中,參與復制的有eden、survivor、old。此時不會對所有老年代區域進行回收,而是根據暫停時間目標優先回收價值高(存活對象少)的區域(這也是GabageFirst 名稱的由來)。復制完成,內存得到釋放。進入下一輪的新生代回收、并發標記、混合收集。
混合收集可能會持續多次。
新生代中存活的對象會被復制到最新的幸存區,之前的幸存區以及老年代中存活的對象,將會放在一個老年代中。
強引用、軟引用,弱引用,虛引用的區別
強引用:只有所有GCRoots對象都不通過【強引用】引用該對象,該對象才能被垃圾回收。只要所有GC Roots能找到,就不會被回收
軟引用:需要配合SoftReference使用,當垃圾多次回收,內存依然不夠的時候會回收軟引用對象
弱引用:需要配合WeakReference使用,只要進行了垃圾回收,就會把弱引用對象回收
虛引用:必須配合引用隊列使用,被引用對象回收時,會將虛引用入隊,由ReferenceHandler線程調用虛引l用相關方法釋放直接內存(虛引用的外部資源)