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空间,再释放掉已使用的两块空间。
  • 老生代
    • 老生代中的对象通常存活时间比较长,每次回收对象释放的空间并不会太多。
    • 在考虑垃圾回收的时间消耗时,除了要看内存空间回收的时间消耗,也要看新对象空间回收的时间消耗。虽然标记-清除算法避免了移动对象的时间消耗,但在分配新的内存空间时,须要当心翼翼地使用碎片空间,形成更多的时间消耗。综合回收和新分配来看,选择标记-整理算法会更优于标记-清除算法
    • 还有另外一种懒整理策略,在进行垃圾回收时,优先选择标记-清除算法;当实在忍受不了空间碎片时在使用标记-整理算法,将空间碎片化为整块内存。
相关文章
相关标签/搜索