3

我正在学习GC。我开始了解以下有关方法调用的机制:

在 JAVA 中的每个方法调用上,都会创建一个新 Frame 并将其推送到堆栈上。此帧包含局部变量、操作数堆栈和对常量池的引用。当任一方法成功完成或该方法抛出未捕获的异常时,将删除框架。

还有以下内容:

JVM 规范不需要 Java 堆栈的特定实现。帧可以从堆中单独分配,也可以从连续内存中获取,或两者兼而有之。

我的问题是:

由于 Frame 是 Stack 的一部分。堆栈是非堆区域的一部分。如果 GC 只负责清理堆区,那么如何以及何时从内存中删除可能驻留在堆中或可能不驻留在堆中的堆栈帧?

如果 GC 未删除帧,则必须有其他线程在运行以清理它们。它是什么?如果它们被 GC 清理,那么这仅意味着如果应用程序遇到与 GC 相关的问题,不必要的方法调用可能是问题的一部分。

我希望我的问题很清楚。

更新:另一个与此相关的问题:

class GCA {

   public static void main(String a[]) {
   Object obj = new Object();
   }
}

据我了解,在上述方法中:

  • 参考变量obj将分配在堆栈帧的局部变量数组上。
  • new Object()将在堆上分配。
  • 清理所obj驻留的帧使用的内存不是 GC 的责任。方法返回时将同步完成。
  • new Object()将被 GC 清理。

以上理解正确吗?

4

1 回答 1

5

由于 Frame 是 Stack 的一部分。堆栈是非堆区域的一部分。如果 GC 只负责清理堆区,那么如何以及何时从内存中删除可能驻留在堆中或可能不驻留在堆中的堆栈帧?

对此有两种看法。一种是 Java 应用程序看待事物的方式。对象在堆上分配,但局部变量(即原始值和对这些对象的引用)存在于堆栈上。从这个意义上说,您所做的陈述是正确的:堆栈帧形成堆栈,与堆不同,因此不受垃圾收集的影响。

另一种观点是 JVM 的内部工作原理,以及它与操作系统的接口。出于效率的原因,它可能决定将一个对象放在堆栈上,即使它在概念上属于堆。这是为了性能,经过逃逸分析。同样,它可能决定将部分概念堆栈保留在它自己管理的堆分配内存中,而不是 JVM 本身使用的本机调用堆栈。这就是规范所指的:JVM 不必使用低级编程意义上的堆栈来实现 Java 调用堆栈。但即使它使用操作系统堆,它仍然不是受 GC 影响的堆的一部分。

如果 GC 未删除帧,则必须有其他线程在运行以清理它们。

不,只有在异步释放帧时才需要另一个线程。但是释放堆栈帧很容易:只要函数退出,就可以释放堆栈帧,因为它的所有数据都超出了范围。因此,离开函数的线程负责清理。完全不涉及异步 GC。

于 2013-09-02T15:43:27.200 回答