java GC算法記錄

簡單記錄下java GC的集中算法策略

1、引用計數法

該計數法使用計數器來活對象和不再使用對象,大概就是給堆中的每個對象分配一個計數器,給該對象賦值後計數器加一,當該對象出了作用域後減一。一旦引用計數器爲0時,就滿足了GC條件。引用計數法有一個致命的缺陷,對循環引用的對象無法回收。

2、標記清除

該策略執行原理是,當堆中有效內存空間被耗盡時,會停止程序,然後進行兩項工作,標記和清除。標記的過程即遍歷所有的GC Roots,所有可達的標記爲活對象。清除即把沒有活對象的標記的全部清除。該策略缺點顯而易見:

a>效率低,需要遍歷所有的GC Roots,而且在GC的時候需要停止程序。

b>標記清除出來的內存空間不是連續的,JVM需要消耗性能去維護這個不連續的內存空間,在下一次分配數組對象內存的時候,去找連續的內存需要消耗額外的性能。

3、複製

複製算法講內存分爲兩個區間,活動空間和空閒空間,當有效內存空間被耗盡時,會暫停程序,把活動空間中的存活對象複製到空閒空間,並且嚴格按照內存地址依次排序,並把存活對象指向新的內存地址,此時情況活動空間的對象,空閒空間變爲活動空間,活動空間變爲空閒空間,然後啓動暫停的程序。可以看出該算法彌補了標記清楚的弊端,但是是以多一部分的內存空間爲代價。

4、分代搜索算法

對象大概可以分爲三大類,新生代,年老代,永生代,新生代即存活週期很短,創建不久就銷燬的對象,比如循環中的變量;年老代,創建後有可能會被銷燬,比如單例對象,數據庫鏈接對象;永生代,一旦創建永生不滅(誇張一點),比如spring 中加載的類信息。

其中,新生代和年老代在Java 堆中,而永生代在方法區中,這裏提一下,在JDK1.8後,方法區的內存與操作系統內存共享。由於永生代的存活週期太長,所以分代搜索算法針對新生代和年老代對象。

新生代對象:

這類對象存活時間週期都很短,所以這類對象最適合複製算法。但是有一個問題,將會耗費50%的內存資源,其實並不會耗費50%,因爲新生代對象的存活率較低,一般的使用兩塊10%的的內存作爲空閒和活動空間,另外的80%內存則是用來給新建對象分配內存的。一旦發生GC,降10%的活動區間與另外的80%的存活對象轉移到空閒區間,剩下90%的內存全部釋放,再開闢10%的空閒內存,依次循環。使用這樣的方式,我們只浪費了10%的內存,這個是可以接受的,因爲我們換來了內存的整齊排列與GC速度,這個策略的前提是,每次存活的對象佔用的內存不能超過這10%的大小,一旦超過,多出的對象將無法複製。

年老代對象:

這類對象存活率較高,而且都是從新生代轉過來的,經歷了多次GC,就像人,獲得久了就成老年人了。新生代轉到老年代有兩種情況:

a>新生代的每個對象都會有一個年齡,對應着經歷GC的次數,每經歷一次CG,就加一,當年齡到達一定程度時,轉爲老年代。而這個條件值是可以在JVM中設置的。

b>新生代的存活對象超過10%時,多餘的對象就會被轉到年老代,這時候年老代就是新生代的備用倉庫。

永生代:

這類對象存活率太高,而且不能使用複製算法,因爲它沒有備用備用倉庫。因此針對永生代一般使用標記清除或標記整理算法。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章