一.对象到底死了没
1.引用计数器
给对象添加一个引用计数器,每当有一个地方引用他,数值就加1,引用失效,计数器就减1。任何时候计数器 为0 的时候就是对象不可用了
问题就是解决不了对象之间相互引用的问题。
public class ReferenceCountingGc { Object instance = null; public static void main(String[] args) { ReferenceCountingGc objA = new ReferenceCountingGc(); ReferenceCountingGc objB = new ReferenceCountingGc(); objA.instance = objB; objB.instance = objA; objA = null; objB = null; } }
这两个对象已经不可能再被引用,但是因为相互引用者,计数值都不为0,所以无法使用垃圾回收器进行回收
2.可达性分析
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
二:引用的问题
判断对象是否可回收其实都和引用相关
jdk1.2之前,引用的定义都很传统
就是如果reference类型的数据存储着另一块内存的起始地址,就称这一块内存代表一个引用
jdk1.2之后对其进行了具体划分
强引用
最常见的一种引用,无论如何不会回收他,即使我他妈报出outofmemory错误,我也不会回收这片区域来解决内存不足的问题
软引用
可有可无的一片区域,如果内存足够,就不会回收他,如果内存不够就会回收他,只要没有回收他,这个对象就可以继续用
和引用队列配合使用,当对象被回收的时候,会把引用放进这个引用队列中
弱引用
也是可有可无的,在垃圾回收线程所管辖的区域内,只要发现有弱引用的对象,就会把这个对象给回收,但是垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些具有弱引用的对象
虚引用
"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
一定会和引用队列配合使用,软引用是“可以”配合使用
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
注意:这里放进引用队列是在回收对象内存之前,而软引用是在回收完成之后放进去的
引用队列:
那么当垃圾回收器准备回收一个被引用包装的对象时,该引用会被加入到关联的ReferenceQueue
就是用来判断对象是否被回收了
三:如何判断一个常量是废弃常量
运行时常量池主要回收的是废弃的常量
假如在常量池中存在字符串 "abc",如果当前没有任何 String 对象引用该字符串常量的话,就说明常量 "abc" 就是废弃常量,如果这时发生内存回收的话而且有必要的话,"abc" 就会被系统清理出常量池。
四:如何判断一个类是无用的类
方法区主要回收的是无用的类
三个条件:
1.该类在堆中的对象是否被回收了
2.用来把该类装进JVM的Classloader是否被回收了
3.该类的Class对象在任何地方都没有被引用,无法在任何地方通过反射访问该类的方法。
虚拟机可以对满足上述 3 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收。
五:垃圾回收算法