JVM系列之垃圾回收算法(一)

2 篇文章 0 订阅

JVM系列之垃圾回收算法(一)

标记阶段:引用计数法

简介

​ 对每个对象保存一个整型的引用计数器属性,用于记录被对象引用的情况。

被对象引用了就+1

引用失效就-1

0表示不可能再被使用,可进行回收

优点

​ 1.实现简单,垃圾便于辨识

​ 2.判断效率高,回收没有延迟性

缺点

​ 1.需要单独的字段存储计数器,增加了存储空间的开销

​ 2.每次赋值需要更新计数器,伴随加减法操作,增加了时间开销

​ 3.无法处理循环引用的情况,是致命缺陷,导致Java的垃圾回收器中没有使用这类算法

引用计数算法的缺陷:

运算结果如下:
在这里插入图片描述

小结

​ 引用计数法,是很多语言的资源回收选择。例如:Python,它更是同时支持引用计数和垃圾回收机制

​ PS:

​ Python解决循环引用:

​ 1.手动解决;

​ 2.使用弱引用,weakref,Python提供的标准库,旨在解决循环引用

标记阶段:可达性分析算法 Java/C#所选择的

基本思路

​ 是以根对象GC Roots)为起始点,按照从上到下的方式搜索被根对象集合所连接的目标对象是否可达;

​ 使用可达性分析算法后,内存中存活的对象都被根对象直接或间接连接着,搜索所走过的路径被称为引用链

​ 如果目标对象没有任何引用链相连,则是不可达的,意味着该对象已经死亡,可以标记为垃圾对象

​ 在可达性分析算法中,只有能够被根对象集合直接或间接连接的对象才是存活的对象

在这里插入图片描述

GC Roots包括的内容

  • 虚拟机栈中引用的对象:例如各个线程被调用的方法中使用到的参数、局部变量

  • 本地方法栈内JNI,引用的对象

  • 方法区中静态属性引用的对象:例如Java类的引用类型静态变量

  • 方法区中常量引用的对象:例如字符串常量池的引用

  • 所有被同步锁synchronized持有的对象

  • Java虚拟机内部的引用

    • 基本数据类型对应的class对象
    • 一些常驻的异常对象,如NPE、OOM
    • 系统类加载器
  • 反映java虚拟机内部情况的JMXBean,JVMTI中注册的回调,本地代码缓存等

  • 除了固定的GC Roots集合之外,根据用户选择的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象临时性的加入,共同构成完整GCRoots集合,比如分代收集和局部回收

    • 如果只针对Java堆中某一块内存区域进行垃圾回收,必须要考虑这个区域的对象可能被其他区域对象所引用,这是需要一并将关联的区域对象加入GC Roots集合中去考虑,才能保证可达性分析的准确性
  • 由于Root采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那么它就是一个Root

  • 如果需要使用可达性分析算法判断内存是否可回收,那么分析工作必须在一个能保障一致性的快照中进行。这点不满足的话,分析结果的准确性就无法保证

  • 这也是GC进行时必须STW的一个重要原因,即使是号称几乎不会发生停顿的CMS收集器中,枚举根节点也是必须要停顿的

对象的finalization机制

简介

  • Java语言提供了对象终止finaliztion机制来允许开发人员提供对象被销毁之前的自定义处理逻辑

  • 当垃圾回收器发现没有引用指向一个对象,即垃圾回收此对象之前,总会先调用这个对象的finalize()方法;

  • finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放,通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件,套接字和数据库链接等;

定义虚拟机的对象可能的三种状态

  • 可触及的——>从根节点开始,可以到达这个对象

  • 可复活的——>对象的所有引用都被释放了,但是对象有可能在finalize()中复活

  • 不可触及的——>对象的finalize()被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为finalize()只会被调用一次

具体过程

  • 判断一个对象ObjA是否可以被回收,至少需要经历两次标记过程

    1、如果对象到GCRoots没有引用链,则进行第一次标记

    2、进行筛选,判断此对象是否有必要执行finalize()方法

    • 如果对象A没有重写finalize()方法,或者finalize方法已经被虚拟机调用过,则虚拟机视为没有必要执行,对象A被判定为不可触及的

    • 如果对象A重写finalize()方法,且还未执行过,那么A会被插入到F-queue队列中,有一个虚拟机自动创建的,低优先级的Finalizer线程触发其finalize()方法执行

    • finalize方法是对象逃脱死亡的最后机会,稍后GC会对F-queue队列中的对象进行第二次标记,如果A在finalize方法中与引用链上的任何一个对象建立了联系,那么在第二次标记时,A会被移除即将回收集合。之后,对象会再次出现没有引用存在的情况下,finalize方法不会再被调用,对象直接变为不可触及状态

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值