根据《JAVA对象结构》介绍了JAVA对象的存储结构,但要如何判断一对象是否存活
引用计数算法:
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
优点:实现简单,效率高(在每个引用丢失的时候判断下计数器,为0就直接回收)
缺点:当对象A成员引用对象B,B对象引用A(循环引用),然后把AB都置空,可他们的计数器仍为1,造成内存泄漏。
可达性分析算法
GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roots是不可达的,所以它们将会判定为是可回收对象。
那么那些点可以作为GC Roots呢?
全局的引用(常量和静态属性)和执行上下文(栈桢中的本地变量表)
1.虚拟机栈(栈桢中的本地变量表)中的引用的对象
2.方法区中的类静态属性引用的对象
3.方法区中的常量引用的对象
4.本地方法栈中JNI(Native方法)的引用的对象
JAVA对象4大引用
根据可达性分析算法,可以很轻松的判断对象是不是已死。但万物没有绝对性,对象也一样,有些对象死活可根据场景判断。
如下左图是对象引用等级的划分,下右图是在内存中的状态关系(软引用和弱引用内存结构是差不多的,因此只画出一种)
从图中得知,JVM 在GC 的时候会判断引用情况
1.如 Object是被强引用着,则不回收
2. 如果通SoftReference对象引用着自己,则判断内存是不是 不足了,不足则清,
3.如果是 WeakReference 对象引用着,则直接回收,
4.如果是 PhantomReference,则直接被清(与ReferenceQueue后面会讲)
对象状态监视ReferenceQueue
Reference是JAVA中对引用表现类。对象拥有4种状态
- Active(当对象被创始时)
- Pending(如果对象有注册ReferenceQueue,当它确认为引用不可达的时候,引用为被改这状态,等待Reference-handler 线程入Queue)
- Enqueued(对象已被加入到ReferenceQueue)
- Inactive(当实例被移出ReferenceQueue中时,这个状态永远都不会再被改变 )
从上面的状态很容易得出ReferenceQueue,是对象的监听对象,只有加入此对象的才可以在回收时被通知。
Object.finalize也是通个ReferenceQueue,JAVA自动实现的,当你重写finalize,则会把此CLASS创建的对象,都扔进一个默认ReferenceQueue中,Finalizer类中有写