GC
須要考慮的三個問題:java
在分析內存區域的時候,咱們把Java
運行時數據區分爲兩個部分:算法
Java
堆、方法區:因爲一個接口中的多個實現類須要的內存可能不同,一個方法中的多個分支須要的內存也不同,只有在程序處於運行期間才能知道會建立哪些對象,所以這些區域的內存分配和回收是動態的。引用的定義:若是reference
類型的數據中存儲的數值表明的另一塊內存的起始地址,就稱這塊內存表明引用。 引用的分類:數組
Object a = new Object()
):只要強引用存在,垃圾回收器永遠不會回收掉被引用的對象。SoftReference
):有用但並不是必須,在系統將要發生OOM
異常以前,將會把這些對象列進回收範圍中進行第二次回收。WeakReference
):非必須對象,被弱引用的對象只能生存到下一次垃圾收集發生前。PhantomReference
):不會對生存時間產生影響,也沒法經過虛引用來取得一個對象實例,設置虛引用的惟一目的就是能在這個對象被垃圾回收器回收時收到一個系統通知。給對象添加一個引用計數器,當有一個地方引用它時就加一,引用失效時就減一,當計數器的值爲零時表示它不可用。 可是它沒法解決相互循環引用問題。安全
經過一系列的稱爲GC Roots
的對象做爲起始點,從這些節點開始向下搜索,所走過的路徑稱爲引用鏈。當一個對象到GC Roots
沒有任何引用鏈時,表示這個對象不可用,GC Roots
的類型有:線程
JNI
**引用的對象。finalize
方法對於內存回收的影響當某個對象在通過可達性分析後,發現它到GC Roots
沒有任何引用鏈時,那麼它會被第一次標記,並進行第一次篩選,篩選的結果有兩種狀況:code
finalize()
方法或者虛擬機已經調用過它的finalize()
方法:直接回收。F-Queue
的隊列中,並在稍後由一個由虛擬機自動創建的、低優先級的Finalizer
線程去執行這個對象的finalize()
方法,如對象要在finalize
方法中拯救本身,只要從新與引用鏈的某個變量關聯便可,那麼在第二次標記時它將被移出「即將回收」的集合,不然它將被回收。這種方法代價高昂,不肯定性大,沒法保證各個對象的調用順序,所以能夠忘記這個方法的存在。對象
對於方法區(HotSpot
中的永久代)主要回收兩部份內容:廢棄常量和無用的類。接口
abc
被放入了常量池中,可是沒有任何一個String
對象引用它,那麼就會被清理出常量池,常量池中其它類(接口)、方法、字段的符號引用也相似。ClassLoader
已經被回收java.lang.Class
對象沒有在任何地方被引用,沒法在任何地方經過發射訪問該類的方法。GC
操做。概念 將可用內存劃分爲大小相等的兩塊,每次只使用其中的一塊,當一塊內存用完了。則觸發一次GC
操做,將活着的對象複製到另外一塊上,而後再把已使用的內存空間一次清理掉。隊列
缺點 將內存縮小爲了原來的一半。內存
如今商業虛擬機採用這種算法的改良版來實現新生代的回收 它把內存按8:1:1
分爲Eden/survivor0/survivor1
三塊: 須要分配內存時,首先嚐試在Eden
區分配,若是Eden
區沒法分配,那麼嘗試把活着的對象放到survivor0
中去:
若是survivor0
能夠放入,那麼放入以後清除Eden
區。
若是survivor0
不能夠放入,那麼嘗試把Eden
和survivor0
的存活對象放到survivor1
中:
survivor1
能夠放入,那麼放入survivor1
以後清除Eden
和survivor0
,以後再把survivor1
中的對象複製到survivor0
中,保持survivor1
一直爲空。survivor1
不能夠放入,那麼直接把它們放入到老年代中,並清除Eden
和survivor0
,這個過程也稱爲分配擔保。適用狀況 因爲複製算法在對象成活率較高時,須要較多的複製操做,效率會變低,因此在老年代中不能採用該算法。
當前商業虛擬機採用的方式,根據對象存活週期的不一樣將內存劃分爲幾塊,通常是新生代和老年代:
Eden/survivor0/survivor1
的分配方式。Minor GC
和Major GC/Full GC
Minor GC
:發生在新生代的垃圾回收動做,很是頻繁,回收速度也較快,採用的垃圾收集器有Serial
、ParNew
、Parallel Scavenge
。Major GC/Full GC
:發生在老年代的GC
,常常伴隨至少一次的Minor GC
,Major GC
的速度通常會比Minor GC
慢十倍以上,採用的垃圾收集器有CMS
、Serial Old
、Parallel Old
。對象優先在Eden
區分配 當Eden
區沒有足夠空間,觸發一次Minor GC
。
大對象直接進入老年代 例如很長的字符串以及數組,常常出現大對象容易致使內存還有很多空間時就提早觸發垃圾收集以獲取足夠的連續空間來「安置」它們。
長期存活的對象將進入老年代 若是Eden
區出生並進過第一次Minor GC
後,仍然存活,而且被成功複製到survivor
區中,那麼對象年齡變爲一,當對象在survivor
中每熬過一次Minor GC
,年齡就增長一,當年齡增長到必定程度,就會晉升到老年代中。
動態對象年齡綁定 若是survivor
空間中相同年齡全部對象大小的總和大於survivor
空間的一半,年齡大於或等於該年齡的對象就能夠進入老年代,無須到達要求的年齡。
空間分配擔保 在發生Minor GC
前,檢查老年代最大可用連續空間是否大於新生代全部對象總空間:
大於,那麼操做是安全的,不對老年代進行Full GC
。
小於,檢查HandlePromotionFailure
設置值是否容許失敗:
Full GC
。在這以後,由於有可能出現某次存活對象激增的狀況,這種屬於冒險行爲,若是出現了擔保失敗(也就是Eden
和survivor0
的存活對象既沒法放入survivor1
,也沒法放入老年代的連續空間中),那麼會在失敗以後對老年代進行Full GC
。Full GC
。Full GC
。