本帖最后由 小猪被骑 于 2020-5-7 11:03 编辑
虚拟机如何确定一个对象是不是垃圾
引用计数算法使用一个引用计数器记录该对象还有多少个引用指针指向该对象,此算法简单高效但需要在代码中进行额外的逻辑处理以防止循环引用导致内存泄露的问题。
让我们来一起看看下面的例子来理解循环引用和内存泄漏两个概念:
在引用计数算法中对于objA和objB是无法回收的,因为它们内部含有对方实例的引用指针,但是除此之外没有其它指针引用这两个对象,也无法访问到这两个对象,JVM无法回收这两个对象,这就导致了内存泄漏。 执行结果如下:
可以看到JVM里面并不是采用引用计数算法,因为在显式指定垃圾收集时JVM确实把这两个对象给回收了,这两个对象的finalize()方法被调用了,这个方法是当对象第一次被回收时被调用的。
那么JVM是如何确定对象是不是一个“垃圾”呢? 对象可达性分析通过一系列的“GC Roots”根对象作为起始节点,一直往下搜索引用关系,搜索过程所走过的路径称为“引用链”。
看下面的代码可以构成一条引用关系链,而objD因为没有指针引用它而成为了垃圾,等待下一次垃圾回收来了结它。
上面代码得到的引用关系链如下图所示:
所以objD会被JVM回收,而objA、objB、objC可以存活下来,如下图所示可以验证这个结果:
固定作为GC Roots的对象主要有以下几种:
虚拟机栈中引用的对象,例如局部变量、形式参数、临时变量······
类静态属性引用的变量,例如类的静态引用类型成员变量
常量引用的对象,例如String str = "alive",字符串常量池中的引用。
同步锁引用的对象,例如synchronized(obj)中被锁住的obj可作为GC Roots
|