这是我参与更文挑战的第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
标记-整理算法每次在回收垃圾对象后,都将后边存活的对象移动到空位上。标记-整理算法能够避免前面两种算法带来的空间碎片或空间浪费问题。但也存在另外一个较大的开销,移动对象的开销。同时,标记-整理算法还会致使回收内存空间时,主程序须要整个中止运行,若是垃圾回收过程过久,对主程序会产生很大影响。设计
因为以上三种算法各有优劣,在实际应用中应当权衡各类利弊后选择算法才能更好地设计垃圾收集器。基于分代收集理论,对于新生代和老生代采用的收集算法并不同。