堆内存是用Java收集的。
是否也收集了垃圾堆?
如何回收堆栈内存?
答案 0 :(得分:36)
堆栈中的内存包含方法参数和局部变量(准确地说:对象的引用和基本类型的变量本身)。如果您离开方法,将自动删除。如果变量是引用(对象),则对象本身位于堆上并由垃圾收集器处理。
因此堆栈不是以与堆相同的方式进行垃圾收集,但堆栈是一种自动内存管理形式(在垃圾收集之前)。
答案 1 :(得分:28)
堆栈不是用Java收集的垃圾。
当方法返回时,释放为给定方法调用分配的堆栈。由于这是一个非常简单的LIFO结构,因此不需要垃圾收集。
堆栈和垃圾收集交互的一个地方是堆栈上的引用是GC根(这意味着它们是决定可达性的根引用)。
答案 2 :(得分:14)
堆栈可能被垃圾收集。但是,在大多数JVM实现中,它被处理为“堆栈”,根据定义,它排除了垃圾收集。
我们称之为堆栈的是方法激活上下文的累积:对于每个被调用的方法,这是包含方法参数,局部变量,隐藏指向上下文的指针的概念结构。调用方法,以及保存指令指针的槽。激活上下文不能从Java语言本身访问。当方法退出时(使用return
或由于抛出的异常),上下文变得无用。碰巧当方法A调用方法B时,可以保证当A重新获得控制时,B的上下文变得无用。这意味着B的上下文的生存期是A的上下文生命周期的子范围。因此,激活上下文(对于给定的线程)可以使用LIFO(“后进先出”)规则进行分配。简单来说,就是一个堆栈:一个新的激活上下文被推送到一堆上下文之上,而顶层的上下文将是第一个被处理掉的。
实际上,激活上下文(也称为堆栈帧)在堆栈顺序中在专用区域中连接。该区域是在线程启动时从操作系统获得的,操作系统在线程终止时将其返回。堆栈的顶部由特定指针指定,通常包含在CPU寄存器中(这取决于JVM是解释还是编译代码)。 “指向调用者上下文的指针”是虚拟的;调用者的上下文必须位于堆栈顺序的下方。 GC不会介入:从线程活动本身创建并同步回收堆栈区域。这也是它在许多语言中的工作方式,例如C,它们根本没有GC。
现在没有什么能阻止JVM实现做其他事情,例如在堆中分配激活上下文并由GC收集它们。这通常不在Java虚拟机中完成,因为堆栈分配更快。但是其他一些语言需要做这些事情,最明显的是那些在使用GC(例如continuations及其Scheme函数)时使用call-with-current-continuation
的语言,因为这些游戏打破了LIFO规则如上所述。
答案 3 :(得分:8)
内存的堆栈部分就像“堆栈”一样工作。我知道这听起来很糟糕,但这正是它的工作原理。数据将添加到顶部,彼此重叠(pushed onto the stack
),并在程序运行时自动从顶部(popped off the stack
)删除。它不是垃圾收集 - 并且它不需要是因为一旦数据从堆栈弹出就自动回收内存。当我说回收时,我并不是说它被取消分配 - 只是当数据被弹出时,堆栈存储器中存储下一个数据的位置会减少。
当然,这并不是说你根本不需要担心堆栈。如果多次运行递归函数,它最终将耗尽所有堆栈空间。如果你调用很多函数也是一样的,特别是如果它们有很多参数和/或局部变量。
但最重要的是,当函数自动进入和离开范围时,使用并回收堆栈的内存。因此,在程序执行结束时,所有堆栈内存都将是空闲的,然后释放回操作系统。
答案 4 :(得分:4)
如果您参考堆栈上使用的内存,则不会进行垃圾回收
java虚拟机使用显式字节码指令来保留和释放堆栈上的内存,这些指令由编译器生成并管理堆栈上的原语(如int,boolean,double和object-references)的生存期。
有计划实现一个所谓的尾调用优化,一旦知道它们不再使用就会从栈中删除一些条目,但我不知道任何已经支持它的jvm。
所以堆栈本身没有垃圾收集,只有编译器生成了push和pop指令来管理内存使用。
堆栈本身是线程的一部分。在创建线程对象时分配堆栈,并在线程终止并且不再引用线程对象后收集垃圾。
答案 5 :(得分:1)
Java中的所有对象都在堆上分配。 (至少就规范而言,实际的实现可能会将它们分配到堆栈上,如果它们透明地表现就像它们在堆上一样。)
究竟什么是收藏品有点微妙。如果对象的唯一引用位于单个堆栈帧中,并且可以显示将不再使用引用,则可以收集该对象。如果该对象仅用于读取字段,则可以向前优化该字段读取,并且比您预期的更早收集对象。
除非您使用的是终结者(或大概是Reference
),否则通常无关紧要。在这种情况下,您应该小心并使用locks / volatile来强制执行happens-before
关系。
当线程停止时,通常会释放整个堆栈。
答案 6 :(得分:1)
堆栈中的所有内容都被垃圾收集器视为全局根。所以,是的,你肯定可以说堆栈是“垃圾收集”。
答案 7 :(得分:0)
没有人,数据会从堆栈中推送和弹出,因为你在方法,方法调用等过程中有内部变量。你不需要关心这一点。
答案 8 :(得分:0)
没有。堆栈不是用Java收集的垃圾。 每个线程都有自己的堆栈,包含:
对于每个方法调用,这些值都作为堆栈帧推送到堆栈。由于堆栈遵循'后进先出'顺序,在每个方法调用结束时,每个堆栈框架都包含所有特定于方法的数据和对象的引用(如果有的话),将被弹出。
因此,一旦方法/程序超出范围,堆栈中的数据将自动清除。