JVM中垃圾回收第二步——如何回收對象

這是我參與更文挑戰的第13天,活動詳情查看:更文挑戰java

  JVM經過可達性分析算法,解決了垃圾回收第一個問題——什麼樣的對象是垃圾對象,應該被回收。在肯定對象必須被回收後,接下來就要考慮如何回收這些垃圾對象。算法

  在如何回收垃圾問題上,主要有三種方法:標記-清除算法、標記-複製算法、標記-整理算法。數組

1 從一道算法題導入

  移除元素 是一個典型的算法題,給你一個數組 nums 和一個值 val,你須要 原地 移除全部數值等於 val 的元素,並返回移除後數組的新長度。markdown

  這是一個簡單的算法題,遍歷整個數組,趕上值爲val的元素時,則刪除該元素並將後面的元素往前移動。經過兩個指針,掃描一次數組,就能夠完成原地移除全部數值等於 val 的元素。這就是標記-整理算法的基本思想。app

class Solution {
    public int removeElement(int[] nums, int val) {
    	int result = 0;
        for(int i = 0;i<nums.length;i++){
        	if(nums[i] != val){
        		nums[result] = nums[i];
        		result++;
        	}
        }
    	return result;        
    }
}
複製代碼

  若是將條件放寬一些,移除元素的時候能夠藉助另外一個數組,將原數組元素值不爲 val 的元素賦值到新的數組上,結果返回新的數組。這個就是標記-複製算法的基本思想。oop

  若是將條件在放寬一些,移除元素的時候能夠不考慮數組是否留有碎片位置,將原數組元素值等於 val 的元素直接賦值爲初始化值。這個就是標記-清除算法的基本思想。post

2 標記-清除算法

  標記-清除算法如同它的名字同樣,整個回收過程分爲標記清除兩個階段。首先標記全部須要回收的對象,完成標記後再原地清除被標記的對象。標記-清除算法雖然簡單,但存在兩個問題:優化

  • 時間問題:標記和清除效率不穩定,若是內存中存在大量須要回收的對象,則JVM須要進行大量的標記和清除動做,致使標記和清除的效率都隨着對象數量的增加而下降;
  • 空間問題:對須要回收的對象直接原地清除,會產生內存碎片,提升了垃圾回收的頻率(若是比較大的對象找不到合適的碎片空間,將會觸發下一次垃圾回收)。

標記-清除算法.png

3 標記-複製算法

  標記-複製算法直接將不須要回收的對象複製到另外一塊空間上,而後清除舊內存空間的全部對象。在JVM中,將堆內存劃分爲大小相等兩塊區域,每次只用其中一塊區域,當區域內存滿了以後,就將存活的對象複製到另外一塊,再清除已使用一塊區域的數據,等待下一次內存回收使用。標記-複製算法能夠規避標記和清除大量垃圾對象的開銷;同時在複製的時候因爲指針一直是遞增,因此回收對象以後並不會產生空間碎片。可是,很明顯存在另外一個問題,空間開銷太大了,每次只能使用堆內存的一半空間。spa

標記-複製算法.png

4 標記-整理算法

  標記-整理算法每次在回收垃圾對象後,都將後邊存活的對象移動到空位上。標記-整理算法能夠避免前面兩種算法帶來的空間碎片或空間浪費問題。但也存在另外一個較大的開銷,移動對象的開銷。同時,標記-整理算法還會致使回收內存空間時,主程序須要整個中止運行,若是垃圾回收過程過久,對主程序會產生很大影響。設計

標記-整理算法.png

5 GC算法的選擇

  因爲以上三種算法各有優劣,在實際應用中應當權衡各類利弊後選擇算法才能更好地設計垃圾收集器。基於分代收集理論,對於新生代和老生代採用的收集算法並不同。

  • 新生代
    • 新生代的特色是對象存活時間短,80%的對象活不過第一次垃圾收集。
    • 所以可使用優化的標記-複製算法進行垃圾回收,在複製時開闢一個較小的空間存放存活的對象,避免過多的空間浪費。
    • 「appel式回收":將新生代的內存空間劃分爲一個較大的Eden和兩塊較小的Survivor,每次使用Eden和其中一塊Survivor,當兩塊空間滿了以後,將存活的對象複製到另外一塊Survivor空間,再釋放掉已使用的兩塊空間。
  • 老生代
    • 老生代中的對象通常存活時間比較長,每次回收對象釋放的空間並不會太多。
    • 在考慮垃圾回收的時間消耗時,除了要看內存空間回收的時間消耗,也要看新對象空間回收的時間消耗。雖然標記-清除算法避免了移動對象的時間消耗,但在分配新的內存空間時,須要當心翼翼地使用碎片空間,形成更多的時間消耗。綜合回收和新分配來看,選擇標記-整理算法會更優於標記-清除算法
    • 還有另外一種懶整理策略,在進行垃圾回收時,優先選擇標記-清除算法;當實在忍受不了空間碎片時在使用標記-整理算法,將空間碎片化爲整塊內存。
相關文章
相關標籤/搜索