Java垃圾回收机制

众所周知,Java是一个编译一次就可在不同系统上运行的语言,这主要得益于JVM虚拟机。

JVM担任着Java内存自动管理的重任,JVM 的⾃动内存管理主要是进⾏对象内存的分配与回收,最核⼼的功能是 堆 内存中对象的分配 与回收。堆 是垃圾收集器管理的主要区域,因此也被称作 GC 堆( Garbage Collected Heap )。

        从垃圾回收的⻆度,由于垃圾收集器基本都采⽤分代垃圾收集算法,堆可以分为:

新⽣代和⽼年代。

新⽣代 Young : Eden 空间、 From Survivor ( s0 )、 To Survivor ( s1 )

⽼年代 Old

对象都会⾸先在 Eden 区域分配,在⼀次新⽣代垃圾回收后,如果对象还存活,则会进⼊ s0 或者 s1 ,并且对象的年龄会加 +1 ,当它的年龄增加到⼀定程度(默认为⼤于 15 岁),就会被晋升到⽼年代中。

分配策略

  • 大象优先在 Eden 区分配
  • ⼤对象直接进⼊⽼年代
  • ⻓期存活的对象将进⼊⽼年代

内存非陪过程中的GC

HotSpot JVM 的内存分配过程中, GC 垃圾回收分类有两⼤种:

1. 部分收集 ( Partial GC ):

        新⽣代收集( Minor GC / Young GC ):只对新⽣代进⾏垃圾收集;

        ⽼年代收集( Major GC / Old GC ):只对⽼年代进⾏垃圾收集;

        混合收集( Mixed GC ):对整个新⽣代和部分⽼年代进⾏垃圾收集;

2. 整堆收集 ( Full GC ):

        收集整个 Java 堆和⽅法区;

如何判断对象可被GC回收?

引用计数法

        就是给对象添加⼀个计数器

  •      每当有⼀个地⽅引⽤它的时候,计数器就加 +1
  •      每当有⼀个引⽤失效的时候,计数器就减 -1

当计数器的值为0的时候,那么该对象就是可被GC回收的垃圾对象。这种⽅案的原理很简单,⽽且 判定的效率也⾮常⾼,但是却可能会有其他的额外情况需要考虑。

跟可达性计数法

        这也是JVM 默认使⽤的寻找垃圾算法。它的原理就是定义了⼀系列的根,我们把它称为 GC Roots ,从 GC Roots 开始往下进⾏搜索,查找的路径我们把它称为 "引⽤链" ,当⼀个对象到 GC Roots 之间没有任何引⽤链相连时,那么这个对象就可以被当做垃圾回收了。

垃圾收集算法

        标记-清除算法(Mark-Sweep)

                算法分为“标记”和“清除”阶段:⾸先标记出所有不需要回收的对象,在标记完成后统⼀回收掉所 有没有被标记的对象。它是最基础的收集算法,后续的算法都是对其不⾜进⾏改进得到。         这种垃圾收集算法会带来两个明显的问题:

       1.效率问题

        2.空间问题(标记清除之后会产生大量不连续的碎片) 

        标记-复制算法(Copying)

              " 标记-复制"收集算法为了解决效率问题。它可以将内存分为⼤⼩相同的两块,每次使⽤其中的⼀ 块。当这⼀块的内存使⽤完后,就将还存活的对象复制到另⼀块去,然后再把使⽤的空间⼀次清理掉, 这样就使每次的内存回收都是对内存区间的⼀半进⾏回收。

         这种算法的缺点也是很明显: 

                浪费过多内存,使现有可用空间变为原先的一半

        标记-整理算法 ( Mark-Compact )        

                标记过程仍然与“标记-清除”算法⼀样,但后续步骤不是直接对可回收对象回收,⽽是让所有存活 的对象向内存空间⼀端移动, 然后直接清理边界以外的内存,这样清理的机制,不会像标记-整理那样 留下⼤量的内存碎⽚。 

        分代收集思想 ( Generational Collection )

                当前虚拟机的垃圾收集都基于分代收集思想,根据对象存活周期的不同,将内存分为⼏个不同的区 域,在不同的区域使⽤不同的垃圾收集算法。 例如:将 Heap 堆分为新⽣代和⽼年代,这样我们就可以根据各个年代的特点选择合适的垃圾收 集算法。在新⽣代中,每次收集都会有⼤量垃圾对象被回收,所以可以选择“标记-复制”算法,只需要 付出少量对象的复制成本就可以完成每次垃圾收集。⽽⽼年代中的对象存活⼏率是⽐较⾼的,⽽且没有 额外的空间对它进⾏分配担保,所以选择“标记-清除”或“标记-整理”算法进⾏垃圾收集。

垃圾收集器

Serial 收集器(新⽣代)

        Serial (串⾏)收集器是最基本、历史最悠久的垃圾收集器。 它是⼀个单线程收集器。它会使⽤⼀条垃圾收集线程去完成垃圾收集⼯作,并且它在进⾏垃圾收集 ⼯作的时候,必须暂停其他所有的⼯作线程( "Stop The World" ),直到收集结束。采⽤“标记-复 制”算法负责新⽣代的垃圾收集。 Serial 收集器的优点是简单⽽⾼效。在单个 CPU 环境下,由于没有线程交互的开销,因此拥有 最⾼的单线程收集效率,所以,它是 Client 模式下的默认新⽣代收集器。

Serial Old 收集器(⽼年代)

        Serial Old 收集器同样是⼀个单线程收集器,采⽤“标记-整理”算法负责⽼年代的垃圾收集.

ParNew 收集器(新⽣代)

        ParNew收集器是一个多线程的垃圾收集器,他是运行Server模式下的虚拟机的首要选择,可以与 Serial Old ,CMS 垃圾收集器⼀起搭配⼯作,新⽣代采⽤“标记-复制算法”,⽼年代 采⽤“标记-整理算法”。

Parallel Scavenge 收集器(新生代)

        Parallel Scavenge 收集器是 JDK1.8 默认收集器,使⽤“标记-复制”算法的多线程收集 器,它看上去⼏乎和 ParNew 都⼀样,同样是多线程的收集器,其它收集器⽬标是尽可能缩短垃圾 收集时⽤户线程的停顿时间,但是 Parallel Scavenge 收集器关注点是吞吐量(⾼效率的利⽤ CPU)。 停顿时间越短就越适合需要与⽤户交互的程序,良好的响应速度能提升⽤户体验。⽽⾼吞吐量 则可以⾼效率地利⽤ CPU 时间,尽快完成程序的运算任务,适合在后台运算⽽不需要太多交互的任 务。 Parallel Old 收集器是⼀个多线程的垃圾收集器,使⽤“标记-整理”算法。在注重吞吐量以 及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器 + Parallel Old 收集 器。

CMS收集器(老年代)

CMS ( Concurrent Mark Sweep )收集器是⼀种以获取最短回收停顿时间为⽬标的收集 器,是 HotSpot 虚拟机第⼀款真正意义上的并发收集器,它第⼀次实现了让垃圾收集线程与⽤户线程 (基本上)同时⼯作。CMS 收集器是⼀种 “标记-清除”算法实现的收集器,它的运作过程相⽐于前⾯ ⼏种垃圾收集器来说更加复杂⼀些。

G1收集器(老年代)

        G1 ( Garbage-First ) 是⼀款⾯向服务器的垃圾收集器,主要针对配备多颗处理器、⼤容量 内存的机器。它不再严格按照分代思想进⾏垃圾回收。

        G1 采⽤局部性收集的思想,对于堆空间的划分,采⽤ Region 为单位的内存划分⽅式:

       G1 垃圾回收器把堆划分成若⼲个⼤⼩相同的独⽴区域( Region )(按照 JVM 的实现, Reg ion 的数量不会超过2048个):每个 Region 都会代表某⼀种⻆⾊, H 、 S 、 E 、 O 。 E 代表 Eden 区, S 代表 Survivor 区,H 代表的是 Humongou s ( G1 ⽤来分配⼤对象的区域,对于 Humongous 也分配不下的超⼤对象,会分配在连续的 N 个 Humongous 中),剩余的深蓝⾊代表的是 Old 区,灰⾊的代表的是空闲的 region 。

         这种思想上的转变和设计,使得G1可以⾯向堆内存任何部分来组成回收集来进⾏回收,衡量标准不 再是它属于哪个分代,⽽是哪块内存存放的垃圾最多,回收收益最⼤,这就是G1收集器的 Mixed GC模 式,即混合GC模式。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值