根据本文垃圾收集的工作原理,有四种gc根:
局部变量通过线程堆栈保持活动状态。这不是真实的对象虚拟引用,因此不可见。无论出于何种目的,局部变量都是gc根。
活动java线程始终被视为活动对象,因此是gc根。这对于本地线程尤其重要
变量。
静态变量由它们的类引用。这一事实使它们成为事实上的gc根。类本身可以被垃圾收集,这将删除所有引用的静态变量。当我们通常使用应用服务器、osgi容器或类加载器时,这一点特别重要。我们将在问题模式部分讨论相关问题。
jni引用是本机代码作为jni调用的一部分创建的java对象。这样创建的对象被特别处理,因为jvm不知道它是否被本机代码引用。这样的对象代表了gc根的一种非常特殊的形式,我们将在下面的问题模式部分更详细地研究它。
在jvm规范中,堆栈帧中的局部变量没有类型,它只是一个字节数组,编译器负责为这些局部变量生成特定类型的指令,例如iload,fload,aload,所以很明显,gc不能仅仅通过查看堆栈帧的局部变量部分来找到对对象的引用。
我的问题是:
gc是怎么找到这些根的?
gc如何在堆栈中找到引用对象而不是其他类型变量(例如iconst存储的变量)的局部变量?
那么gc如何找到这些对象的字段来创建一个可访问的树呢?
它是否使用jvm本身定义的指令来查找这些对象?
最后,这句话的意思是什么?
这不是真实的对象虚拟引用,因此不可见
1条答案
按热度按时间mdfafbf11#
gc是怎么找到这些根的?
jvm提供了一个用于查找根的内部(c/c++)api。jvm知道java堆栈帧在哪里,java类的静态帧在哪里,活动jni对象句柄在哪里,等等(它知道,因为它参与了它们的创建,并跟踪它们。)
gc如何在堆栈中找到引用对象而不是其他类型变量的局部变量。
jvm保存每个方法的信息,这些信息表示每个堆栈帧中的哪些单元格是引用变量。gc可以找出每个堆栈帧对应的方法。。。就像
fillInStackTrace
可以。(例如常量)
这其实并不相关。常数(即。
final
不要得到特殊待遇。那么gc如何找到这些对象的字段来创建一个可访问的树呢?
jvm为每个类保留信息,说明哪些静态字段和示例字段是引用变量。每个对象的头中都有一个引用类的字段。
整个过程被称为“标记”,在您看到的页面中有描述。
它是否使用jvm本身定义的指令来查找这些对象?
我不知道你在问什么。但“可能是的”。gc是jvm的一个组件,所以所做的一切都是“由jvm定义的”。
最后,这句话的意思是什么?
这不是真实的对象虚拟引用,因此不可见
可能是说线程的堆栈不是java对象。。。这是真的。但我想你应该问问那本电子书的作者;看看下面https://www.dynatrace.com/resources/ebooks/javabook/ 他们的名字。
您添加了以下内容:
在jvm规范中,堆栈帧中的局部变量没有类型,它只是一个字节数组,编译器负责为这些局部变量生成特定类型的指令,例如iload,fload,aload,所以很明显,gc不能仅仅通过查看堆栈帧的局部变量部分来找到对对象的引用。
事实上,这不是真的。正如@holder提醒我的,验证器通过模拟初始化它们的字节码的效果来推断stackframe中的单元类型。此外,类文件中的每个方法都有一个
StackMapTable
包含用于帮助(和加速)验证器类型确定的信息的属性。稍后,gc可以从jvm获得推断的类型信息。
(理论上,gc也可以利用
StackMapTable
确定局部变量何时超出范围的信息。。。在方法中。但在热点jvm中显然不是这样;请参阅stackmaptable是否影响垃圾收集行为?)在那本电子书中对垃圾收集的描述是(有意地)简短和高层次的。但这是真实的大多数描述,你会发现。细节很复杂。
如果您真的想(并且需要)了解gc的工作原理,我的建议是:
要了解当前的java实现是如何工作的,请阅读openjdk源代码。
追踪并阅读sun和oracle关于javagcs的研究论文。
找一本关于垃圾收集的好教材。