Java对象的生与死

读书笔记:《深入理解Java虚拟机》第三章

回收的区域:
     垃圾收集重点关注的区域是方法区和堆,因为只有这两个区域使用不可预估。而栈、程序计数器等因为是线程私有,方法调用进栈出栈有条不紊。

引用计数法:
     在对象中添加一个引用计数器,当被引用的时候,计数器加一,当计数器为0的时候,表示对象没有引用,这是一个常规、简单、高效的方法,但是这种方式难以解决相互循环引用的问题(即A、B对象中有变量互相引用对方对象。)

可达性分析算法:
     主流商用语言均使用的算法,基本思想是如果对象有“GC ROOTS”相关联的引用链,进行可达性分析,如果不可达表示当前对象与GC ROOTS没有了引用链。

由此,可以作为GC ROOTS对象的有:

  • 栈中引用的对象
  • 方法区中静态类属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈引用的对象(JNI)

java的引用类型:

  • 强引用类型
    • 强引用类型是new出来的,所以虚拟机即使抛出内存溢出错误,也不会回收这部分内存。
  • 软引用类型
    • 软引用属于可以回收但是弃之可惜的,所以只有当即将内存溢出的时候,然后回收这部分对象,如果还是依然不够,那就抛出异常。
  • 弱引用类型
    • 弱引用只能存活到下一次垃圾收集之前。
  • 虚引用类型
    • 一个对象设置虚引用类型的唯一目的是收到一条系统回收的通知。

对象被回收的两次标记过程:
     经过上面,我们已经知道,不可达对象就表示此对象没有了引用链,那么他们会成为垃圾收集器的目标,此时他们会被标记一次!!!但是并不是被回收,而是被判“缓刑”,真正宣判对象完蛋至少经历2次标记过程

     第一次被标记并进行一次筛选,筛选的条件就是是否有必要执行finalize()方法,没有必要执行的前提是该对象没有覆盖finalize()方法或者系统执行过此方法,那么,如果有必要执行就会将此对象放入一个F-queue的队列,等待一个叫Finalizer的低级线程执行finalize方法,此时finalize方法是一个对象逃脱回收的最后机会!GC会在队列中进行小规模的第二次标记,如果对象没有在finalize方法中自救(与可作为GC Roots的对象发生关联的话),就会真正被回收。

方法区回收:
废弃常量无用的类,这是这方法区回收被关注的地方!

废弃的常量是指没有被其他任何对象引用,比如“abc”,没有String对象引用到它这个字面量,那么它就需要移除常量池

无用的类,满足三个条件才能成为无用的类:

  • 中再也没有该类的任何实例
  • 该类的ClassLoader被回收
  • 该类对应的java.lang.Class对象没有被引用到,无法通过反射进行访问该类方法
原文地址:https://www.cnblogs.com/Kevin-1992/p/12608393.html