JVM -垃圾回收算法 - 垃圾回收(2)

垃圾回收算法

    • 垃圾回收算法
    • 分代收集理论
    • 标记 - 清除算法
    • 标记 - 复制算法
    • 标记- 整理算法
    • 内存分配和策略
        • 空间分配的一个担保
    • 常用参数

垃圾回收算法

其实根据如何判断对象死亡的方式将垃圾回收算法可以判定为两种 “引用计数式垃圾回收 ” 和 “ 追踪式垃圾收集 ” ,这两种也被称为 “直接垃圾收集” 和 “间接垃圾收集”。而JVM 主要使用就是后者,也是下文介绍的重点。

分代收集理论

很多人喜欢将分代收集作为一种收集算法,其实这个更偏向于是一种理论,在往后的垃圾回收器中,也是采用了分代收集理论为基础,使用不同的垃圾回收算法。
分代假说:

  • 弱分代假说:绝大多数对象都是朝生夕灭的
  • 强分代假说:熬过越多次垃圾收集的过程的对象就难以消亡。

这两个假说就奠定了垃圾回收器的原则:将对象分成不同的区域,针对不同的区域采用不同的算法,使用不同的垃圾回收器进行收集。

几个概念:

  • 部分收集(Partial GC):指的是不是完整的收集整个堆中的垃圾
    • 新生代收集(Minor GC):对新生代收集
    • 老年代收集(Major GC):对老年代进行收集
    • 混合收集(Mixed GC):对整个新生代和部分老年代进行收集
  • 整堆收集(Full GC):对整Java 堆和方法区进行垃圾收集

标记 - 清除算法

这个很好理解,根据GC roots 将存活的对象进行标记,剩下的对象就是需要清除的对象,将需要的清除的对象进行标记,然后进行清除就行。
这个算法的缺点很明显:

  • 就是会产生大量的内存碎片
  • 当需要清除的对象过多的时候,标记和清除的过程也偏多,效率太低。

标记 - 复制算法

这个算法就是对前者效率低的一种解决。
将存放对象的区域划分为两半,一半用来存储对象,当用完之后,进行垃圾回收,将存活的对象进行标记,然后复制到另外一块区域上,再将用过的区域整个进行清除。
特点:

  • 这个算法会产生比较大的内存开销,因为只存了一半
  • 这个算法清除的效率很高,也没有内存碎片

这个算法广泛用于新生代的收集,原因就是新生代的特点就是----- 新生代的对象中有 98% 的对象在第一次收集中就会被收集掉。
新生代空间分配:

  • 新生代会分为一块较大的 Eden 空间和 两块较小的 Survivor 空间,8 : 1 : 1 。
  • 当使用的时候就使用 一块 Eden 和 一块 Survivor 区域。
  • 当空间不足或者发生垃圾回收的时候,将存活的对象都复制到剩余的一块 Survivor 区域上 。

这块有个问题,如果存活对象太多会怎么样?
这个就需要一个担保,其实就是老年代的一种担保策略,当这些复制的存活对象放不下的时候,就会直接进入老年代

标记- 整理算法

当复制算法中的存活对象过多的时候,复制的操作也会变多,这个是一种效率很低的过程,如果不按照1:1 的分配空间的话,就需要老年代的额外空间对其进行分配担保。所以老年代不会使用这种算法。

这个算法同样也是先标记存活对象,再将存活的对象向内存空间的一端进行移动,然后直接清除掉边界以外的内存。

这种对对象的移动操作是一种负重操作,必选全部暂停用户的线程。 也被称为 Stop The World。

因为如此,所以在老年代的回收器中,Parallel Old 比较关注吞吐量,所以采用的是标记整理,而CMS 垃圾收集器,比较关注 低延迟,所以采用的标记清除,但是在内存碎片过多时影响对象的分配时,就会使用标记-整理算法收集一次。

内存分配和策略

Java 中的自动的内存管理主要解决了两个问题,自动为对象分配内存和回收内存。基本上都是在堆上分配内存。

  • 大多数对象都是在新生代的Eden 区分配对象,当新生带的区域对象不够的时候就发起一次 Minor GC 。
  • 大对象直接进入老年代。很长的字符串或者很大 的数组。
  • 长期存活的对象进入老年代,当对象在新生代存活 熬过了 Minor GC 年龄会+1 ,当年龄 大于等于15 的时候就会被进去老年区( -XX:MaxTenuringThreshold =15)
  • 动态年龄判断,在Survivor 中当年龄大于或者等于某个值的时候的对象所占用的内存超过空间的一半,就会直接升入老年代。

空间分配的一个担保

上次提到复制算法中,新生代的GC 需要老年代的额外空间进行担保,如果老年代的连续空间大于新生代分配总大小,那么 Minor GC 一定会成功,肯定是安全的。如果不够,就要允许担保失败。这里有个参数( -XX: HandlePromotionFailure )看是否允许冒险。

如果不允许,当老年代内存不够担保,直接会进行Full GC
如果允许,会以以往进入老年代大小的平均值 的内存空间大小进行担保,如果进入老年代的值突然增大,就会担保失败,老老实实的进行Full GC 。

常用参数

含义 参数
堆初始大小 -Xms
堆最大大小 -Xmx 或 -XX:MaxHeapSize=size
新生代大小 -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )
幸存区比例(动态) -XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy
幸存区比例 -XX:SurvivorRatio=ratio
晋升阈值 -XX:MaxTenuringThreshold=threshold
晋升详情 -XX:+PrintTenuringDistribution
GC详情 -XX:+PrintGCDetails -verbose:gc
FullGC 前 MinorGC -XX:+ScavengeBeforeFullGC

你可能感兴趣的:(JVM,面试题,笔记,算法,java,面试)