• Java 垃圾回收之垃圾回收算法


      1、对象被判断为垃圾的标准

    没有被其它对象引用

    2、判断对象是否为垃圾的算法

    1)引用计数算法

    2)可达性分析算法

    3、引用计数算法

    1) 通过判断对象的引用数量来决定对象是否可以被回收

    2)每个对象实例都有一个引用计数器,被引用则+1, 完成引用则-1

    3) 任何引用计数为0的对象实例可以被当作垃圾收集

    4、引用计数算法优缺点

    优点: 执行效率高,程序执行受影响较小

    缺点: 无法检测出循环引用的情况,导致内存泄露。(如父对象引用子对象,子对象中引用父对象,引用计数永远不可能为0)

    5、可达性分析算法

    通过判断对象的引用链是否可达来决定对象是否可以被回收。

    6、什么对象可以作为GC Root对象

    1) 虚拟机栈中的引用的对象(栈桢中的本地变量表)

    2) 方法区中的常量引用的对象

    3)方法区中的类静态属性引用的对象

    4)本地方法栈中JNI(Native方法)的引用对象

    5)活跃线程的引用对象

    7、垃圾回收算法

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

    标记: 从根集合进行扫描,对存活的对象进行标记

    清除: 对堆内存从头到尾进行线性遍历,回收不可达对象内存

    缺点: 容易造成碎片化

    如上图,Sweep后,有三个不连续的内存,如果要分配的对象比较大(比如有占用三个),就无法分配到刚才Sweep的区域。

    2)复制算法(Copying)(适用对象存活率低的场景)

    分为对象面和空闲面

    对象在对象面上创建

    存活的对象被对象面复制到空闲面

    将对象面所有对象内存清除

    复制算法:

    解决碎片化问题

    顺序分配内存,简单高效

    适用于对象存活率低的场景

    3) 标记-整理算法(Compacting)

    标记: 从根集合进行扫描,对存活的对象进行标记

    清除: 移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。

     

    4) 分代收集算法(Generational)

    垃圾回收算法的组合拳

    按照对象生命周期的不同划分区域以采用不同的垃圾回收算法

    目的:提高JVM的回收效率

    jdk6,jdk7

     

     Jdk8及其以后的版本

      

    GC的分类

    Minor GC

    Full GC

    年轻代: 尽可能快速地收集掉那些生命周期短的对象

    Eden区(为什么叫Eden去,伊甸园,人类的起源)

    两个Survivor区(from和to)

    年轻代垃圾回收过程演示

    1、假设每个对象的大小是一样的。Eden最多能保存4个对象, S0最多能保存3个,S1最多能保存3个

    2、当Eden被四个对象占满。 就会触发一次Minor GC

     3、里面还有一块绿色是存活的,就会被复制到其中一块Survivor区。如S0

    4、 之后Eden区被清除,这就是首次Minor GC的过程

    5、接着我们假设Eden区被填满了。此时又会触发一次Minor GC

    6、测试将Eden和S0的存活对象拷贝到S1区。同时对对象的年龄+1。S1从to区变成了from区。S0则从to区变成了from区

    7、拷贝完成后,Eden区和S0区都会被清空。

     这样就完成了第二次Minor GC。

    8、之后假设Eden区又满了。触发第三次Minor GC。这时候假设S1中有一个无用对象,需要被清除。

    9、需要将Eden区和S1区的存活对象拷贝到S0中。同时各自存活对象的年龄+1

    10、拷贝完成后Eden和S1区被清空

     周而复始,对象在Survivor区每经过一次Minor GC,其年龄就会被+1,当对象的年龄达到某个值时,(默认是15,也可以通过参数 -XX:MaxTenuringThreshold进行调整),这些对象会成为老年代。但这也不是一定的,对与一个要分配较大连续内存的对象,比如Eden区和Survivor都装不下,就会进入老年代。

    Minor GC使用复制算法,在进行内存分配时,不需要考虑内存碎片等复杂情况。

    在分代收集算法中,对象如何晋升到老年代

     经历一定Minor次数依然存活的对象

    Survivor区中或Eden区中放不下的对象

    新生成的大对象(通过-XX:+PretenuerSizeThreshold 控制大对象的大小)

    常用的调优参数

    -XX:SurvivorRatio : Eden和Survivor的比值,默认8:1

    -XX:NewRatio: 老年代和年轻代内存大小的比例。 如值为2 新生代是老年代的2倍,即新生代占据内存的1/3  那新生代和老年代总大小是如何决定的,就是-XMX决定

    -XX:MaxTenuringThreshold: 对象从年轻代晋升到老年代经过GC次数的最大阈值。

    老年代: 存放生命周期较长的对象

     老年代的内存比新生代的内存大,大概的比例一般是2:1

    使用算法有:

    标记-清理算法

    标记-整理算法

    老年代:Full GC和Major GC

    当触发老年代的垃圾回收时,通常会伴随着对新生代的堆内存的回收.这就是所谓的Full GC

    Major GC通常是和Full GC是等价的。

    Full GC比Minor GC慢,但执行频率低

    触发Full GC的条件

    1、老年代空间不足

    2、永久代空间不足(针对JDK 7 以及以前的版本)。这就是为什么用元空间代替永久代的原因,目的是降低Full GC的频率,减少GC的负担,提升效率。

    3、CMS GC时出现promotion failed, concurrent mode failure.

    4、Minor GC晋升到老年代的平均大小大于老年代的剩余空间。

    5、调用System.gc()

    6、使用RMI来进行远程RPC或管理的JDK应用,每小时执行1次Full GC

    .

  • 相关阅读:
    PHP 中 parent、self、static、$this 的区别 & 后期静态绑定详解
    PHP中for和foreach背后发生了什么和关于迭代器的理解
    PHP中this,self,parent三个关键字
    PHP文件指针操作
    php中Session使用方法详解
    关于PHP日期时间的主要函数
    php获取checkbox复选框的多个选项的内容
    PHP中的11个魔术方法总结:__construct,、__destruct、__call等
    PHP类的自动加载机制实现方法分析
    C#学习笔记(二)
  • 原文地址:https://www.cnblogs.com/linlf03/p/12173507.html
Copyright © 2020-2023  润新知