垃圾收集算法

1.标记-清除算法

“标记-清除”算法是最基础的垃圾收集算法,分为“标记”和“清除”两个阶段;当堆中的有效内存空间内耗尽的时候,就会停止整个程序,然后进行标记,清除工作。
在这里插入图片描述

  • 标记:首先将所有死亡对象(在上一篇文章中有说到,如果判断对象是否存活)打上标记
  • 清除:清除的过程将遍历堆中所有的对象,将所有被标记的对象全部清除。
    缺点:
    1.效率比较低,因为要遍历所有的对象,并且在进行垃圾回收过程中,需要停止应用程序。
    2.这种方式清理出来的空闲内存不连续,空间碎片太多可能会导致当程序在以后的运行过程中需要分配较大对象时无法找到足够大的连续内存而不得不提前触发下一次垃圾收集动作。
2.复制算法

为了解决效率问题,出现了“复制”算法。该算法是将可用内存一分为二,每次只使用其中一块。当有效内存空间消耗尽时,JVM将暂停程序运行,开启复制算法GC线程,GC线程会将活动区间内的存活对象,全部复制到空闲区间去,并且会严格按照内存地址依次排序,同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。垃圾对象全部留在了原活动区间,被一次性清理。
这样使得每次都是对其中一块进行内存回收,内存分配时也就不用考虑内存碎片等情况,只要移动堆顶指针,按顺序分配内存即可。
在这里插入图片描述
缺点:
1.由于将内存划分为两个区间,一个区间被空着,浪费了一半的内存。
2.如果大部分对象都是存活状态,那么需要将绝大部分的对象都复制一遍,再将所有引用地址重置,比较浪费时间。

现在的商业虚拟机都采用这种算法来回收新生代。因为新生代的对象大部分存活时间都不长,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性复制到另外一块Survivor空间上,最后清理掉Eden和刚才被使用的Survivor空间。

3.标记整理算法

“标记-整理”算法与标记-清除”算法类似,分为标记和整理两个阶段。

在这里插入图片描述

  • 标记:首先将所有死亡对象(在上一篇文章中有说到,如果判断对象是否存活)打上标记
  • 整理:将所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
    缺点: 效率较低
4.分代搜集算法

当前商业虚拟机的垃圾收集都采用“分代收集”算法,分代收集算法根据对象的存活周期的不同,将内存划分为几块区域。分为新生代(Young)、老年代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的算法。

在这里插入图片描述

  • 新生代(Young)
    分为三个区,一个Eden区,两个Survivor区(from区和to区)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到survivor区中,当这个survivor区满时,此区的存活对象将被复制到另一个survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的。将在指定次数回收后仍然存活的对象迁移到老年代中。
  • 老年代(Tenured)
    老年代存放从年轻存复制过来的存活的对象(长期存活的对象),以及大对象。
  • 持久代(Perm)
    用于存放静态文件,如java类、方法等。

分代收集算法会根据每一块内存的特点采用最适合的收集算法。在新生代中,对象存活率低,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而在老年代中,因为对象存活率高、没有额外的空间对它进行分配担保,就必须使用“标记-清除”或“标记-整理”算法来进行垃圾回收。

回收方法区

很多人认为方法区(永久代)是没有垃圾收集的,Java虚拟机规范中也说过可以不要求虚拟机在方法区实现垃圾收集,而且在方法区进行垃圾收集的性价比一般比较低。在堆中,尤其是新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,而在永久代中的垃圾收集效率远低于此。’
永久代中的垃圾收集主要是回收废弃常量和无用的类。回收废弃常量与回收Java堆中的对象非常类似,以常量池中字面量的回收为例,如果一个字符串“abc”已经进入了常量池中,但是当前系统没有任何一个String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,那么如果在这个时候发生内存回收,而且必要的话,这个“abc”常量就会被从常量池中清除。
判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件相对苛刻许多。类需要同时满足下面3个条件才能算是“无用的类”。

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
    虚拟机可以对满足上述3个条件的无用类进行回收,但可以回收不代表一定会被回收。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值