垃圾回收
一、什么时候需要回收
Java使用可达性分析(Reachability Analysis)来判断对象是否存活。
这个算法的基本思想是:通过一系列称为"GC Roots"的对象作为起始点,从这些结点向下搜索,搜索所走过的路称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,证明这个对象时不可用的。被判断为可回收对象。
可做为GC Roots的对象包括:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI(Native方法)引用的对象。
注意:并不是被判断为可回收对象后,该对象一定会被回收。
对象被判定为可回收后,会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况视为“没有必要执行”。
如果对象被判定“没有必要执行”,这个对象将会放置在一个叫做F-Queue的队列之中,稍后在虚拟机自动建立的、低优先级的Finalizer线程去执行它(在线程里执行对象的finalize方法)。
如果对象在finalize()方法中成功拯救了自己(重新与引用链上的任何对象建立关联),在第二次标记的时候,该对象被移出“即将回收”的集合;反之,对象被回收。
其他可以回收的情况(仅仅是可以回收,但不一定回收)
- 废弃常量
没有任何String对象引用常量池中的"abc"常量,也没有其他地方引用了这个字面量,"abc"为废弃常量 - 无用的类(同时满足以下三个条件)
堆中不存在该类的任何实例;
加载该类的ClassLoader已经被回收;
该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法(就是没有地方用到xx.Class);
二、怎么回收
具体回收操作是通过垃圾收集器实现的。
常见的垃圾收集器有G1,CMS等。
回收算法
- 标记-清除
顾名思义,标记需要回收的对象,然后清楚。但这样容易造成清理后的内存空间不是连续的。 - 标记-整理
同样,先标记,将存活的对象都移动到一边,清理另一边的空间。 - 复制
将内存分为两块,每次只用其中一块,当这块用完了,将存活着的对象复制到另一块,当前这块全部清理掉。 - 分代
把堆分为新生代和年老代(Java8以前还有持久代),根据年龄特点回收。
这篇文章建议配合我的上篇文章一起阅读 Java虚拟机(二) - 对象 创建流程、内存分配
[1] 周志明 · 深入理解Java虚拟机 :机械工业出版社