深入理解java虚拟机——判断对象的“死活”

来源:互联网 发布:y2y的网络意思 编辑:程序博客网 时间:2024/06/04 19:03

在第三章中,讲诉垃圾算法之前,需要明确一件事,即:哪些对象可以算作是“垃圾”,从而被回收。
在java中,堆中的对象如果可以确认不会再被引用,那么它就可以被回收了,虚拟机判断对象会不会被引用,有如下几种套路:

  • 引用计数算法

    引用计数算法是指:创建的每一个对象都有一个与之关联的计数器,这个计数器记录着该对象被使用的次数,垃圾收集器在进行垃圾回收时,对扫描到的每一个对象判断一下计数器是否等于0,若等于0,就会释放该对象占用的内存空间,同时将该对象引用的其他对象的计数器进行减一操作

    引用计数算法的优点:随时可以进行回收。在程序运行中,如果jvm发现某一对象的引用计数器为0,那么jvm就可以回收该对象的内存空间,这样可避免Full GC时带来的STW停顿。

  • 可达性分析算法

    • HotSpot VM使用可达性分析算法判断对象是否需要回收。
    • 简单来说,可达性分析算法的思路就是“某些”对象作为GC Roots(根节点),从这些对象开始向下搜索,搜索走过的路线就叫引用链(Reference Chain),当一个对象不在引用链上时,就说明这个对象是不可用的,那么这个对象就可以被回收了!

一般来讲,以下几种类型的对象可作为GC Roots:

  1. 虚拟机栈(本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI引用的对象

分别简单解释下上边四类引用:

  1. 栈对应的是java中方法的调用,那么虚拟机栈中引用的对象,就是当前调用方法的引用类型的参数/局部变量/临时值
  2. 类静态属性的引用,只有在类被卸载之后,才会被回收内存,因为需要存活的时间很长,所以作为GC Roots之一
  3. 这个地方我的理解可能不准确,方法区的常量通常是某种需要共用的标识(比如是某一种枚举类型的标志),所以它的引用对象应该是那种会在各处被使用的对象,故作为GC Roots之一(若有大神发现不对,请指教小弟,不胜感激,后续如果弄明白了,也会第一时间更新上来)
  4. (比如Java虚拟机的内部代码)

下面补上两个很有用的参考:

  1. 知乎上R大的答案,[点击查看]
  2. Eclipse帮助,[点击查看]

另外简短提一句,可达性分析算法中不可达的对象,在经历两次标记之后才会真正被回收,这期间只要对象能重新回到引用链中,那么该对象将躲过回收。

  • 回收方法区

    回收方法区通常指回收两部分内容:废弃常量和无用的类

    1. 废弃常量:当一个常量没有任何对象引用的时候,发生回收时,如果必要(可能是指内存严重不足的情况吧,0 0),该常量会被清理出常量池。
    2. 无用的类:判定一个类是无用的类,需满足一下三个条件,
      1. 堆中没有任何一个该类的对象实例
      2. 加载该类的类加载器已经被回收
      3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

    满足以上条件时,该类可以被回收,注意,是可以,不是必须。

0 0
原创粉丝点击