您的位置:首页 > 编程语言 > Java开发

【java进阶】java虚拟机垃圾回收详解(四)--内存分代与回收策略

2018-08-31 16:12 429 查看

目录

1.并行(Parallel)与并发(Concurrent)

2.Minor GC和Full GC

3.年轻代

4.老年代

在讨论回收策略之前,有必要明白以下几个概念:

1.并行(Parallel)与并发(Concurrent)

并行:多个cpu同时执行一段逻辑代码,是真正的同时。在垃圾收集中指多条回收线程并行工作,此时用户线程处于等待状态

并发:指通过CPU调度算法,让用户感觉是同时在执行,但实际并不是同时执行的。在垃圾回收中指用户线程和回收线程同时执行,用户程序在继续运行,垃圾回收线程在另一个CPU上运行。(用户线程和回收线程不一定是并行的,可能会交替执行)。

2.Minor GC和Full GC

Minor GC:新生代GC, 发生在新生代的垃圾收集动作。java对象大多数都具备朝生夕灭的特性,所以Minor GC执行非常频繁,Minor GC执行速度一般也比较快。

Full GC:老年代GC, 也叫做Major GC。执行速度一般比Minor GC慢10倍。

Java虚拟机根据对象的生命周期不同,把堆分为年轻代(Young Generation),老年代(Old Generation)和永久代(Permanent Generation)三块。

堆是java虚拟机管理的最大的一块内存。程序所有的实例对象都存放在堆中。堆是垃圾回收最频繁的一块区域。堆内存分代是为了提高对象创建和垃圾回收的效率。如果不分代,所有新建对象和生命周期比较长的对象堆放在一起。回收时要遍历整个堆内存。严重影响GC效率。

分代之后情况就不同了,新建的对象,生命周期短的对象存放在新生代,生命周期长的对象存放在老年代。静态信息,类信息存放在永久代。新生代中对象大多“朝生夕灭”,进行频繁的GC,代价降低很多。老年代中对象生命周期比较长,不频繁GC。永久代中只有运行时常量池和类卸载回收,一般很少回收。这样垃圾回收操作的效率大大的提高了。

3.年轻代

年轻代分为两个部分,伊甸园区(Eden)和存活区(Survivor)。存活区又分为相同大小的FromSurvivor和ToSurvivor两个区,一般叫做S0区和S1区。这三个区域默认的大小比例为:8:1:1。

新建对象存放在Eden区(除了大对象,大对象直接进入老年代。)。如果Eden区内存不够,则发生一次Minor GC。如果对象在第一次Minor GC之后仍然存活,并且能够被Survivor容纳,对象将给移入Survivor区,并且对象的年龄被设置为1。对象每熬过一次Minor GC,对象的年龄增加1,当年龄增加到一定值(默认为15,可以通过-XX:MaxTenuringThreshold参数设置。),对象被移入老年代。

还有一点需要说说,Survivor区中对象晋升,不一定要等到年龄够了,才晋升到老年代。如果Survivor区中有一个年龄的对象(相同年龄)大小的总和大于Survivor区空间的一半,那么这个年龄以及比这个年龄还要老的对象都要晋升到老年代。

再聊大对象问题:

大对象是指需要连续内存空间的java对象,典型的大对象就是那种很长的字符串以及数组。大对象对虚拟机来说是一个坏消息,经常会造成本来还有内存空间,但不得不触发一次GC整理出来较大的连续空间。更糟糕的是“朝生夕灭”的“短命”大对象,写代码的时候应该尽量避免使用大对象。

虚拟机提供一个-XX:PretenureSizeThreshold参数,大于这个参数的对象直接分配到老年代。这样避免在Eden和Survivor之间多次复制。(年轻代的垃圾收集器基本都是复制算法。。。)

4.老年代

晋升到老年代中的对象生命周期一般比较长,在老年代中GC发生的频率一般较低。

发生Minor GC的空间担保问题:

新生代采用复制算法,为了提高内存利用率,只使用其中的一个survivor空间作为轮换备份。如果出现大量MinorGC后仍然存在的情况,需要老年代进行空间担保,把Survivor无法容纳的对象直接进入老年代。前提是老年代还有空间容纳这些对象。所以会用每次晋升到老年代的对象大小的平均值作为经验值,与老年代剩余空间做比较来判断是否需要进行一次Full GC。

 

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: