堆栈帧、方法调用和垃圾回收

3
我正在学习GC。我了解到有关方法调用的以下机制:
在JAVA中的每个方法调用时,都会创建一个新的Frame并将其推入堆栈。该帧包含局部变量、操作数堆栈和对常量池的引用。当方法成功完成或方法抛出未捕获的异常时,将删除该帧。
同时还有以下信息:
JVM规范不需要Java堆栈的特定实现。帧可以从堆中单独分配,也可以从连续的内存中获取,或者两者兼而有之。
我的问题是:
由于Frame是Stack的一部分。Stack是Non-Heap区域的一部分。如果GC只负责清理堆区域,那么如何以及何时从内存中删除可能驻留在堆中的堆栈帧?
如果Frames不是由GC删除的,则必须有其他线程运行以清理它们。那是什么?
如果它们是由GC清除的,那么这意味着如果应用程序遇到与GC相关的问题,则不必要的方法调用可能是问题的一部分。
我希望我的问题很清楚。
更新: 另一个与此相关的问题:
class GCA {

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

根据我的理解,在上述方法中:
  • 引用变量obj将被分配在堆栈帧的本地变量数组中。
  • new Object()将被分配在堆上。
  • 清理包含obj的帧所使用的内存不是垃圾回收的责任。它将在该方法返回时同步完成。
  • new Object()将由垃圾回收器清理。
以上理解正确吗?

进一步澄清疑问的扩展问题,附带代码示例。请查看。 - Learn More
1
在自己的问题上发表评论不会通知回答者您的评论。所以我能再次看到这里纯属运气。我同意您的理解,但有一个警告,编译器可能分析您的代码,认识到Object从未传递出该方法,因此可能决定同步释放它。这是一种不改变语义的优化。 - MvG
1个回答

5
由于Frame是Stack的一部分,Stack又是Non-Heap区域的一部分。如果GC只负责清理Heap区域,那么在什么情况下,可能或不可能驻留在Heap中的Stack frames将从内存中删除?
对此有两种观点。一种是Java应用程序看到的方式。对象在堆上分配,但局部变量(即原始值和对这些对象的引用)存在于堆栈上。从这个意义上讲,你所说的语句是正确的:stack frames形成堆栈,与堆不同,因此不受垃圾回收的影响。
另一个视图是JVM的内部工作方式及其与操作系统的接口。出于效率考虑,它可能会决定将对象放在堆栈上,即使在概念上它属于堆。这是为了性能而进行逃逸分析。同样,它可能会决定将概念上的堆栈的一部分保留在堆分配的内存中,它自己管理,而不是JVM本身使用的本机调用堆栈。这就是规范所指的:JVM不必使用低级编程意义上的堆栈来实现Java调用堆栈。但是即使它使用操作系统堆,那也不是受GC控制的堆的一部分。
如果Frame不是由GC删除的,那么必须有其他线程运行来清除它们。
不。只有在异步释放帧时才需要另一个线程。但释放堆栈帧很容易:只要函数退出,帧就可以被释放,因为所有数据都超出了范围。因此,离开函数的线程负责进行清理。异步GC没有参与其中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接