JVM垃圾收集算法

jvm一般把内存区域(或者说堆内存)分为新生代和老年代,作这样的区分主要是为了方便收集,新生代的对象大部分都是朝生夕死,所以进行回收十分频繁,而老年代则是那些一直没有被收集过得内存,进行垃圾回收次数较少。这样就不用了对整块内存进行回收。因而才有了“Minor GC”“Major GC”“Full GC”这样的回收类型的划分。手机算法也有标记-清除算法,标记-复制算法,标记-整理算法。
标记可以理解为jvm会对将要回收的内存进行一次标记,这些标记过得内存区域是可能进行回收的,然后在第二次标记如果发现这个内存已经被标记过,那么这个内存就会被回收。
第二次被标记的对象会放入一条队列中(名为 F-Queue)低优先级去执行finalize() 方法。所以对象可以覆盖这个方法去进行一次自救,但是这个自救有且只能有一次,当第二次对象被标记在被回收时,jvm是不会去调用finalize() 方法。这个finalize() 方法最好不要覆盖去实现。
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println(“yes, i am still alive 😃”);
}

@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println(“finalize method executed!”);
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
// 因为 Finalizer 方法优先级很低,暂停 0.5 秒,以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println(“no, i am dead 😦”);
}
// 下面这段代码与上面的完全相同,但是这次自救却失败了
SAVE_HOOK = null;
System.gc();
// 因为 Finalizer 方法优先级很低,暂停 0.5 秒,以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println(“no, i am dead 😦”);
}
} }`
上述代码摘自于《深入理解java虚拟机》。执行结果为:
finalize method executed!
yes, i am still alive 😃 no, i am dead 😦
可以看出finalize() 方法纸杯调用了一次。
说了标记,下面来理解一下
标记-清除算法:
标记清除算法就是对内存中被标记的内存进行回收,但是这种算法有个很大的缺点就是内存块不连续,可能不利于后续分配。所以在此算法的基础上升级出标记-复制算法。
标记-复制算法
标记很好理解还是对需要回收的内存进行标记,复制顾名思义就是讲原来的内存分成两块一摸一样的内存。比如说A,B两块。先使用A块内存,在回收完毕后将还存活的内存整块移动到B块,只需要按顺序分配内存即可,但是这样的缺陷很大,就是可使用的内存少了一半。如下图:
在这里插入图片描述
所以有了后续优化,因为每次存活的内存都会很少,所以Andrew Appel提成了一种优化策略法是把
新生代分为一块较大的 Eden 空间和两块较小的 Survivor 空间,Eden:Survivor = 8 : 1。正常情况下使用一块Eden和一块Survivor内存。当进行内存回收后会把存活的内存全部分配到另一块新的Survivor上。当然可能会出现Survivor内存不够当前存活对象分配,所以,当Survivor 空间不足以容纳一次 Minor GC 之后存活的对象时,就需要依赖其他内存区域(实际上大多就是老年代)进行分配担保(Handle Promotion)。
标记-整理算法
标记还是那个标记,整理其实就是针对清楚后内存的整理,将杂乱的内存按照顺序排列,更好的理解其实这个算法可以叫做标记-清除-整理。
在这里插入图片描述
但是这种算法也有缺陷,尤其是在老年代这种每次回收都有大量对象存活区域,移动存
活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动
操作必须全程暂停用户应用程序才能进行[1],这就更加让使用者不得不小心翼翼地权衡
其弊端了,像这样的停顿被最初的虚拟机设计者形象地描述为“Stop The World。(摘自深入理解java虚拟机)。
所以如何选取那种算法要看程序更加关注的方面。关注吞吐量就使用整理算法,关注低延迟则使用清除算法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值