专栏首页Java患者对象的最后一次救赎

对象的最后一次救赎

什么样的对象会被回收

我们都知道当堆内存不够用的时候,会进行垃圾回收,回收的则是对象,那么哪些对象会被作为”垃圾“被回收呢?

答案是:判断算法

引用计数算法

虚拟机会给每一个对象设置一个计数器,每当对象被引用的时候计数器就会+1,当引用断掉的时候计数器-1。当引用计数器的值为0时则表示该对象没有被引用到,可以被回收。

在此,对象A--对象B--对象C,都有被引用,而对象D没有被引用,那么对象D会被回收。

我们可以看到引用计数法的实现非常简单,判定效率也是很高的,但是主流的Java虚拟机并没有使用引用计数来管理内存,最主要的原因是如果对象之间存在相互循环引用的时候,因为相互引用,计数器的值就不会永远变为0,所以永远都不会被当成”垃圾“回收。

可达性算法分析

这个算法的基本思路就是通过一系列的称为”GC Roots“的根对象作为起始节点集合,从这些节点开始根据引用关系向下搜索,搜索的过程中,所走过的路径称为”引用链“,如果当某个对象到GC Roots间没有任何的引用链连接,或者说从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。

我们可以看到对象1到对象4因为跟GC Roots中有引用链连接,所以是存活的对象,而对象5到对象7与GC Roots中没有引用链连接,即使他们相互引用,也会被回收。

GC Roots 对象

在Java体系中,固定可作为GC Roots的对象包括以下几种:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,比如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  • 方法区中类静态属性引用的对象,比如java类的引用类型静态变量。
  • 方法区中常量引用的对象,如字符串常量池中的引用。
  • 本地方法栈中引用的对象。
  • Java虚拟机内部的引用,如基本类型对应的Class对象,一些异常对象等(NullPointException、OutOfMemoryError)等,以及系统类加载器。
  • 同步锁持有的对象
  • 本地代码缓存等。

那么上面这些作为GC Roots对象集合,为什么他们可以是GC Roots对象呢?

GC管理的主要区域是Java堆,一般情况下只针对堆内存进行垃圾回收。而方法区、栈跟本地方法不被GC所管理,所以选择这些内存区域的对象作为GC Roots。

对象的最后一次救赎

刚刚我们上面谈到通过可达性算法来判断对象是否已经死亡,其实在可达性分析算法中判定为不可达的对象,也并不一定就会死亡的,要判定一个对象死亡,至少需要两次的标记过程。

  • 如果对象在进行可达性分析后发现与GC Roots没有引用链连接,那么它会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都认为”没有必要执行“。
  • 如果这个对象被判定为有必要执行finalize()方法,那么该对象将会被放置在一个F-Queue队列中,并在稍后由一条虚拟机自动建立、低调度优先级的Finalizer线程去执行他们的finalize()方法。
  • 这里的执行是指虚拟机会触发这个方法开始运行,但不一定会等待它结束。这样做的原因是如果某个对象的finalize()方法执行比较缓慢,或者极端的来说发生了死循环,将可能导致F-Queue队列中的其他对象处于等待,甚至导致整个内存回收子系统的奔溃。
  • 这个时候finalize()方法是对象逃脱死亡的最后一次机会,稍后收集器将对F-Queue队列中的对象进行第二次小规模的标记,如果对象要在finalize()方法中拯救自己,只要重新与引用链上的任何一个对象建立关联即可,比如把自己(this)赋值给某个类的变量或则和对象的成员变量,那么第二次标记时它将被移出”即将回收“的集合中;当然这个时候对象还没逃脱,那么就基本上会被回收了。

本文分享自微信公众号 - Java患者(gh_3a16ffdedb6a),作者:Zero

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 继续造轮子-MongoDB写日志

    MongoDB我们都知道是一个Nosql,其次MongoDB可以存储海量数据,正好满足我们的需求,日志本身就会很多,基本每一个操作可能都会保存一条日志记录,如果...

    用户7386338
  • 前端常见面试题

    Hello,安雅兮又来啦!!!现在是网络招聘的高峰期,过完年的部分小伙伴们可能面临着求职的问题。哈哈哈,Don't worry。贴心的小编姐姐已经给小主们整理好...

    用户7386338
  • 从面向过程出发到函数式编程(上篇)

    java8为我们引入的Lambda表达式、Stream ApI以及方法引用,它们为了java提供函数式编程的支持,虽然目前JDK已经出现到14的版本了,但是小编...

    用户7386338
  • jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法

    什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1,引用数量为0的时候,则说明对象没有被任何引用指...

    黎明大大
  • MAT内存分析工具使用

    itliusir
  • 领域驱动设计-软件中的对象

    软件中的对象 About DOMAIN-DRIVEN DESIGN 领域驱动设计是一种思维方式,目的在于处理具有复杂问题的软件项目。在传统的瀑布软件开发模型中,...

    知然
  • 深入探究JVM之对象创建及分配策略

    Java是面向对象的语言,所谓“万事万物皆对象”就是Java是基于对象来设计程序的,没有对象程序就无法运行(8大基本类型除外),那么对象是如何创建的?在内存中又...

    夜勿语
  • Java对象的结构与对象在内存中的结构

    当我们在Java中使用new这个指令创建一个对象的时候,对象的创建到底经过了什么样的一个过程呢?

    星如月勿忘初心
  • JavaScript之对象学习

    对象是一种非常重要的数据类型,他是一种自包含的数据集合,包含在对象里面的数据可以通过属性和方法两种形式来访问; 1.属性是隶属于某个特定对象的变量; 2.方法是...

    郑小超.
  • 面试官:你说你熟悉jvm?那你讲一下并发的可达性分析

    那天刚刚下完雨,路过这个地方的时候,一瞬间就被这五颜六色的门板和自行车给吸引了,于是拍下了这张图片。看到这张图片的时候我就很开心,多鲜活、多舒服的画面呀。

    why技术

扫码关注云+社区

领取腾讯云代金券