浅谈Java垃圾回收(GC)

什么是GC?

  • 垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。自动垃圾回收机制就是要解决三个问题:
  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

哪些内存需要回收?

  • Java的堆存放了几乎所有的对象,GC需要回收内存中已经 “死” 的对象。如何判断对象 “生死”。常见的有引用计数法和可达性分析算法。
引用计数法
  • 为对象添加一个计数器,当一个地方引用对象时,计数器 +1,引用实效时,计数器 -1。任意时刻当计数器为0就判定对象已死。

  • 优点:判断简单高效,大部分情况下是一个不错的算法。

  • 缺点:无法解决对象间循环引用问题,所以主流java虚拟机未采用该算法。

可达性分析算法
  • 算法基本思想是通过“GC Roots”的对象作为起点,从这个节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链与之相连,则证明对象时不可到达(已死)。

  • 下图object5,object6,object7虽然相连,但是没有一个引用链能关联到“GC Roots”, 所以系统判定它们时可已回收的对象,如果用引用计数法则无法判定。

什么时候回收

  • 现代的Java虚拟机都是采用“分代收集算法”,Eden满了Minor GC,升到老年代的对象大于老年代剩余空间Full GC。
  • Eden,Minor GC, Full GC等参见如何回收部分解释。

如何回收

  • 垃圾收集器通常会帮我们在后台自动进行垃圾回收。这部分具体我们需要了解收集算法,分代收集,垃圾收集器。
垃圾收集算法
  • 标记-清除算法

  • 最基础的收集算法,算法分为标记和清除两个阶段。首先标记出所有需要回收的对象,然后统一回收。

  • 问题:1-效率不高,标记和清除两个阶段的效率都不高; 2-空间问题,标记清除之后会产生大量的内存碎片,碎片太多导致需要分配大对象无法找到连续的内存触发新的GC。

  • 复制算法

    • 复制算法为了提高效率,讲内存划分为两个大小相等的两块,每次使用其中的一块。当这一块内存用完了,将存活的对象复制到另一块。然后将使用过的内存清理,每次对内存整个半区回收,并且不会有内存碎片。
    • 问题:将内存缩小为原来的一半,牺牲比较大。
    • 现代的商业虚拟机都是采用这种算法收集新生代,由于绝大多数对象时“朝生夕死”,所以并不需要1:1的划分内存。内存分为一块较大的Eden空间和两块较小的Survivor空间。回收时将Eden区和Survivor中还存活的对象一次性复制到另外一块Survivor,然后清理到Eden和Survivor。HotSpot虚拟机默认的Eden和Survivor比例是8:1。如果空闲的Survivor空间不够存储存活对象,则需要依赖老年代进行担保。
  • 标记-整理算法

  • 复制收集算法在对象存比较高需要进行多次复制操作,效率变低。如果不想浪费50%的空间,就需要额外的空间进行担保,防止所有对象都存活的情况。

  • 标记整理算法标记过程和标记清除一样,后续的步骤不只是对对象清理,而是让所有存活对象都移动到一端,然后直接清理掉端边界的内存。

分代收集
  • 当前商用的虚拟机都是采用“分代收集”算法。一般将Java堆分为新生代和老年代,根据各个年代的特点采用适当的收集算法。
  • 新生代对象存活率低,适合采用复制收集算饭。老年代对象存活率高,并且没有额外空间担保,适合标记-整理算法收集。
垃圾收集器
  • 目前最常用的是CMS(Concurrent Mark Sweep)收集器,G1(Garbage-First)则是未来最先进的收集器。
CMS收集器
  • CMS收集器是一个以获取最短回收停顿时间为目标的收集器。
  • 它收集过程分为:初始标记,并发标记,重新标记,并发清除四个步骤。初始标记,并发标记需要“stop the world”。初始标记就是标记一下“GC Roots”能关联的对象,并发标记就是进行“GC Roots” Tracing过程。重新标记是修正并发标记期间用户程序运行导致标记变动的纪录。
  • CMS的优点是并发收集,低停顿。
  • CMS有三个明显的缺点:
  • 1.CPU资源敏感:在并发阶段,虽然不会导致用户线程停顿,但是占用了一部分的线程资源导致应用程序变慢。
  • 2.无法处理浮动垃圾,可能出现”Concurrent Mode Failure“失败导致另一次Full GC。由于并发清理阶段用户还在运行,产生新的垃圾,CMS无法在当次收集清理它们,这些就是浮动垃圾。CMS收集阶段需要预留空间给用户程序,如果预留的内存无法满足程序需要,则会出现”Concurrent Mode Failure“失败,此时收集器进行老年代收集,停顿时间变长。
  • 3.CMS是基于”标记-清除“算法实现的收集器,意味着收集结束会有内存碎片。通过参数可能整理碎片,代价是停顿时间变长。
G1收集器
  • G1是未来替换CMS的收集器,在G1之前的收集器进行收集的范围都是整个新生代或老年代,G1将Java堆划分成很多大小相等独立区域(Region),虽然保留和新生代老年代的概念,但是它们不是物理隔离,都是一部分Region(无需连续)的集合。他具有以下特点:

  • 并行并发:G1能充分利用多CPU,多核环境的硬件优势,使用多CPU减少"stop the world"停顿的时间。

  • 分代收集:与其他收集器一样,分代的概念在G1得以保留。

  • 空间整合:与CMS的“标记-清理”不同,G1从整体上看是“标记-整理”,从局部(两个Region)之间看是基于“复制”算法实现。无论如何,G1收集之后没有空间碎片。

  • 可预测停顿:建立可预测停顿时间模型,能让使用者在一个长度为M毫秒的时间片段内,消耗在垃圾回收的时间不超过N毫秒。

  • Remembered Set: 在G1中,Region之间的对象引用虚拟机都是使用Remembered Set 来避免全堆扫描的。每个Region都有一个对象的Remembered Set,虚拟机发现Reference类型数据进行读写操作产生一个Write Barrier暂时中断写操作,检查Reference是否处于不同Region之中,如果是则更新Region的Remembered Set。

  • G1收集器的运作步骤:初始标记,并发标记,最终标记,帅选回收。

  • 初始标记,并发标记,最终标记和CMS过程类似,帅选回收首选对各个Region的回收价值和成本进行排序,更具用户所期望GC停顿时间制定回收计划。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值