我正在研究GC。我开始了解关于方法调用的以下机制:
在JAVA中的每个方法调用中,都会创建一个新的Frame并将其推送到堆栈上。此框架包含局部变量,操作数堆栈和对常量池的引用。 当任一方法成功完成或方法抛出未捕获的异常时,框架将被删除。
还有以下内容:
JVM规范不要求Java堆栈的特定实现。帧可以从堆中单独分配,也可以从连续的内存中获取,或者两者都可以。
我的问题是:
由于Frame是Stack的一部分。 Stack是Non-Heap区域的一部分。如果GC只负责清理堆区域,那么堆栈中可能存在或不存在堆栈的帧如何以及何时从内存中移除?
如果GC没有删除帧,则必须运行其他一些线程来清理它们。它是什么? 如果他们被GC清理,那么这只是意味着如果一个应用程序运行到GC相关的问题,不必要的方法调用可能是问题的一部分。
我希望我的问题很明确。
更新: 与此相关的另一个问题:
class GCA {
public static void main(String a[]) {
Object obj = new Object();
}
}
根据我的理解,在上面的方法中:
obj
将在Stack Frame的局部变量数组上分配。 new Object()
将在Heap上分配。obj
所在帧所使用的内存不是GC的责任。当方法返回时,它将同步完成。 new Object()
。以上理解是否正确?
答案 0 :(得分:5)
由于Frame是Stack的一部分。 Stack是Non-Heap区域的一部分。如果GC只负责清理堆区域,那么堆栈中可能存在或不存在堆栈的帧如何以及何时从内存中移除?
这有两种观点。一个是Java应用程序看待事物的方式。对象在堆上分配,但局部变量(即原始值和对这些对象的引用)存在于堆栈上。从这个意义上说,你所做的陈述是正确的:堆栈框架形成堆栈,与堆不同,因此不受垃圾收集。
另一种观点是JVM的内部工作方式及其与操作系统的接口。出于效率的原因,它可能决定将对象放在堆栈上,即使它在概念上属于堆。逃逸分析后,这是为了表现。同样,它可能决定将概念堆栈的一部分保留在它自己管理的堆分配内存中,而不是JVM本身使用的本机调用堆栈。这是规范所指的:JVM不必在低级编程意义上使用堆栈来实现Java调用堆栈。但即使它使用操作系统堆,它仍然不是受GC影响的堆的一部分。
如果GC没有移除帧,则必须运行其他一些线程来清理它们。
没有。如果要异步释放帧,则只需要另一个线程。但释放堆栈帧很容易:只要函数退出,就可以释放帧,因为它的所有数据都超出了范围。因此,离开函数的线程负责清理。根本不涉及异步GC。