這是我參與更文挑戰的第13天,活動詳情查看:更文挑戰java
JVM經過可達性分析算法,解決了垃圾回收第一個問題——什麼樣的對象是垃圾對象,應該被回收。在肯定對象必須被回收後,接下來就要考慮如何回收這些垃圾對象。算法
在如何回收垃圾問題上,主要有三種方法:標記-清除算法、標記-複製算法、標記-整理算法。數組
移除元素 是一個典型的算法題,給你一個數組 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
標記-清除算法如同它的名字同樣,整個回收過程分爲標記和清除兩個階段。首先標記全部須要回收的對象,完成標記後再原地清除被標記的對象。標記-清除算法雖然簡單,但存在兩個問題:優化
標記-複製算法直接將不須要回收的對象複製到另外一塊空間上,而後清除舊內存空間的全部對象。在JVM中,將堆內存劃分爲大小相等兩塊區域,每次只用其中一塊區域,當區域內存滿了以後,就將存活的對象複製到另外一塊,再清除已使用一塊區域的數據,等待下一次內存回收使用。標記-複製算法能夠規避標記和清除大量垃圾對象的開銷;同時在複製的時候因爲指針一直是遞增,因此回收對象以後並不會產生空間碎片。可是,很明顯存在另外一個問題,空間開銷太大了,每次只能使用堆內存的一半空間。spa
標記-整理算法每次在回收垃圾對象後,都將後邊存活的對象移動到空位上。標記-整理算法能夠避免前面兩種算法帶來的空間碎片或空間浪費問題。但也存在另外一個較大的開銷,移動對象的開銷。同時,標記-整理算法還會致使回收內存空間時,主程序須要整個中止運行,若是垃圾回收過程過久,對主程序會產生很大影響。設計
因爲以上三種算法各有優劣,在實際應用中應當權衡各類利弊後選擇算法才能更好地設計垃圾收集器。基於分代收集理論,對於新生代和老生代採用的收集算法並不同。