

————— 第二天 —————





————————————





下面我們一起來研究這三個問題,
問題1:哪些是需要回收的?
首先我們需要知道如何哪些垃圾需要回收?判斷物件是否需要回收有兩種演算法,一種是參考計數演算法、一種是可達性分析演算法,
參考計數演算法
參考計數演算法很簡單,它通過記錄物件被參考的次數從而判斷該物件的重要程度,如果該物件被其它物件參考,則它的參考計數加一,如果洗掉對該物件的參考,那么它的參考計數就減一,當該物件的參考計數為0時,那么該物件就會被回收,


參考計數存在什么問題呢?當有兩個物件相互參考時,由于它們互相參考對方所以計數都不為零,這就會導致這兩個物件無法回收,
所以,Java虛擬機采用的是另一種方法來判斷物件是否存活,它就是可達性分析演算法,


可達性分析演算法
可達性分析演算法,首先要確定一系列根物件(GC Roots),并從根物件為起點根據物件之間的參考關系搜索出一條參考鏈(Reference Chain),在參考鏈的物件就存活,而不在參考鏈的物件就認定為可回收物件,
有一個比喻十分恰當:可達性分析演算法就好比是在清洗葡萄串,我們可以從一根枝提起一大串葡萄,他們就像一串參考鏈,而沒有和參考鏈相連的物件就像是散落在池子里的葡萄,可以回收,


虛擬機堆疊中參考的物件(正在運行的方法使用到的變數、引數等)
方法區中類靜態屬性參考的物件(static關鍵字宣告的欄位)
方法區中常量參考的物件,(也就是final關鍵字宣告的欄位)
本地方法堆疊中參考的物件(native方法)
Java虛擬機內部的參考,(系統內部的東西當然能作為根了)
問題2:有哪些重要的垃圾回收演算法?
學會判斷記憶體中哪些垃圾需要回收后,我們就需要掌握幾個重要的垃圾回收演算法,
標記-清除演算法
標記-清除法是最基本的一種垃圾回收演算法,總的來說分為兩步:
標記

標記所有需要回收的物件(灰色),也就是在做垃圾的判定,
清除

將標記為灰色的部分,清除掉,
需要注意的是:所謂的清除,并不需要真正地把整個記憶體的位元組進行清零操作,只需要把空閑物件的起始結束地址記錄下來放入空閑串列里,表示這段記憶體是空閑的就行,


優點速度快,只需要做個標記就能知道哪一塊需要被回收,但是他的缺點也是致命的,
他的主要缺點有兩個:一是執行效率不穩定,二是會涉及到記憶體碎片化的問題,
可能有人會問,碎片化是什么意思呢?上面所描述的這個堆疊,通過標記清除法雖然是清除了空間,但是清除出來的記憶體是大量的不連續記憶體碎片,像下面的這塊物件,明明整體都有位,卻因為不連續無法放入,這是標記-清除演算法最大的缺點,



所謂標記復制演算法和標記整理演算法,都是對標記清除演算法缺點的改進,所以才說標記清除演算法是最基礎的方式,
標記-整理演算法
與標記-清除演算法不同,標記-整理演算法是移動式的,他會讓所以存活的物件都向記憶體空間一端移動,然后清除到邊界以外的記憶體,
標記

移動



是什么樣的弊端呢?標記-整理演算法涉及到了物件的移動,在整理階段,由于移動了可用物件,需要去更新參考,效率就低了,
標記-復制演算法
標記-復制演算法,相比前面的比較不同,他將記憶體空間分為兩塊,在垃圾回收時將正在使用的記憶體中的存活物件復制到未被使用的記憶體塊中,然后呢再清除正在使用的記憶體塊中的所有物件,最后再交換兩個記憶體的角色,最后完成垃圾回收,
大體來看可以分為 這么幾個步驟:
復制

清空

易位

不難看出,標記復制演算法不需要標記算是提升了效率,此外他也不會引數碎片問題,
但是,標記復制演算法的缺點也是十分明顯的,它需要雙倍空間,

問題3:垃圾回收的具體流程是怎樣的?
既然說JVM虛擬機不會單獨采用某種演算法,而是會結合三種演算法讓他們協同作業,其具體的實作就是java虛擬機里的分代垃圾回識訓制,



上圖所示,就是Java堆記憶體的劃分,為什么需要這么劃磁區域呢?那是因為我們的java物件壽命都是不同的,有的可能需要長時間使用,而有的可能用完就可以丟去,于是我們可以根據其生命周期的不同特點,進行不同的垃圾回收策略,
總的來說,新生代的垃圾回收比較頻繁,老年代很久才觸發一次垃圾回收,新生代處理的都是一些朝生夕死的物件,而老年代回收的是更有價值的,會長時間存活的物件,
舉個很好理解的例子:新生代處理垃圾,就像是處理生活日用垃圾,而老年代處理的垃圾,更像是過年大掃除,家里實在太多垃圾了來一次重清理,大掃除清理的垃圾,都是在家中存放時間較長的,往往可能曾經很受用,如今退役了先放著過年再打掃清除掉,


每一次,我們創建一個物件,都會在伊甸園區占據一定記憶體大小,漸漸地伊甸園就滿了,當我們再要創建物件時,就會發現空間不夠了,

這時,就會觸發一次垃圾回收,新生代觸發的垃圾回收有個稱呼叫做MinorGC,
MinorGC觸發后,伊甸園區就會對各個物件進行可達性分析,從而知道哪些物件應該作為垃圾被清理,
MinorGC在這里采取的是標記復制演算法,它將有用的物件存放到幸存區to,然后把伊甸園中的物件清除掉,

進入幸存區的幸運兒,將會被標記上一個“幸運值”,代表他們抗住了多少次清理,

最后,幸存區to和幸存區from還需要互動一下位置,這里不是指物理位置交換,而是說,它倆的定義發生了交換,下次就是左邊那個為幸存區to,右邊的為幸存區from了,
換句話說,幸存區to始終是空的,
我們再模擬多幾次,加深一下印象:
假如又進來了不少物件,伊甸園又滿了!

那就會觸發一次MinorGC,把幸存者移步到幸存區to,其他一律清空,

最后別忘了,幸存區from和幸存區to又要再交換一下”位置“,

...














轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/286381.html
標籤:java
