58

堆内存是 Java 中的垃圾收集器。

堆栈垃圾是否也被收集?

堆栈内存是如何回收的?

4

9 回答 9

39

堆栈上的内存包含方法参数和局部变量(准确地说:对象的引用和原始类型的变量本身)。如果您离开该方法,它将自动删除。如果变量是(对对象的)引用,则对象本身位于堆上并由垃圾收集器处理。

所以堆栈不像堆那样被垃圾收集,但堆栈是它自己的一种自动内存管理形式(它早于垃圾收集)。

Thomas Pornin 给出了更详细的答案,请查看更多详细信息。

于 2010-03-15T13:46:15.350 回答
29

堆栈不是 Java 中的垃圾收集器。

当方法返回时,为给定方法调用分配的堆栈被释放。由于这是一个非常简单的 LIFO 结构,因此不需要垃圾收集。

堆栈和垃圾收集交互的一个地方是堆栈上的引用是 GC 根(这意味着它们是决定可达性的根引用)。

于 2010-03-15T13:46:11.180 回答
14

堆栈可能会被垃圾收集。然而,在大多数 JVM 实现中,它被当作一个“堆栈”来处理,根据定义,它排除了垃圾收集。

我们所说的堆栈是方法激活上下文的累积:对于每个调用的方法,这是一个概念结构,它包含方法参数、局部变量、指向调用方法的上下文的隐藏指针和保存指令的槽指针。Java 语言本身无法访问激活上下文。当方法退出时上下文变得无用(使用return或因为抛出异常)。碰巧当方法 A 调用方法 B 时,可以保证当 A 重新获得控制权时,B 的上下文变得无用。这意味着 B 的上下文的生命周期是 A 的上下文的生命周期的子范围。因此,可以使用 LIFO(“后进先出”)规则分配激活上下文(对于给定线程)。简而言之,堆栈:一个新的激活上下文被压入上下文堆栈的顶部,并且顶部的上下文将首先被释放。

在实践中,激活上下文(也称为堆栈帧)按堆栈顺序连接在专用区域中。该区域是在线程启动时从操作系统获得的,而操作系统在线程终止时将其取回。栈顶由一个特定的指针指定,通常包含在 CPU 寄存器中(这取决于 JVM 是解释代码还是编译代码)。“指向调用者上下文的指针”是虚拟的;调用者的上下文必须位于堆栈顺序的正下方。GC 不干预:堆栈区域是从线程活动本身同步创建和回收的。这也是它在许多根本没有 GC 的语言(例如C )中的工作方式。

现在没有什么能阻止 JVM 实现做其他事情,例如在堆中分配激活上下文并让 GC 收集它们。这在 Java 虚拟机中通常不会完成,因为堆栈分配更快。但是其他一些语言需要做这样的事情,最值得注意的是那些在使用 GC 的同时玩延续的语言(例如Scheme及其call-with-current-continuation函数),因为这样的游戏打破了上面解释的 LIFO 规则。

于 2010-03-16T11:38:55.777 回答
8

The stack part of the memory works just like a "stack". I know it sounds bad, but that's exactly how it works. Data is added to the top, on top of each other (pushed onto the stack) and is automatically removed from the top (popped off the stack) as your program runs. It is not garbage collected - and it doesn't need to be since that memory is automatically reclaimed once data is popped off the stack. And when I say reclaimed I don't mean it gets de-allocated - it's just that the location in the stack memory where the next data will be stored is decreased, as data is popped off.

Of course that's not to say that you don't need to worry at all about the stack. If you run a recursive function many times it will eventually use up all the stack space. The same if you call many functions, especially if they have many parameters and/or local variables.

But the bottom line is that the memory of the stack is used and reclaimed as functions enter and leave scope - automatically. So at the end of your program's execution all the stack memory would be free and then released back to the operating system.

于 2010-03-15T13:50:12.387 回答
5

如果您引用堆栈上使用的内存,则不是垃圾收集。
java虚拟机使用显式字节码指令来保留和释放堆栈上的内存,这些指令由编译器生成并管理堆栈上的int,boolean,double和object-references等原语的生命周期。
已经计划实施所谓的尾调用优化,一旦知道它们不再使用,就会从堆栈中删除一些条目,但我不知道任何 jvm 已经支持这一点。
所以没有堆栈本身没有垃圾收集,只有编译器生成推送和弹出指令来管理内存使用。

堆栈本身是线程的一部分。堆栈是在线程对象创建时分配的,并且在线程终止并且不再引用线程对象后进行垃圾收集。

于 2010-03-18T15:43:40.363 回答
1

Java 中的所有对象都分配在堆上。(至少就规范而言,如果它们透明地表现得好像它们在堆上一样,实际实现可能会将它们分配到堆栈上。)

究竟什么是可收藏的有点微妙。如果对一个对象的唯一引用在单个堆栈帧中,并且可以证明该引用不会被再次使用,则可以收集该对象。如果该对象仅用于读取一个字段,则该字段读取可能会向前优化,并且该对象的收集时间可能比您预期的要早。

Reference除非您使用终结器(或可能是s),否则这通常无关紧要。在这种情况下,您应该小心并使用 locks/volatile 来强制建立happens-before关系。

当线程停止时,通常整个堆栈将被释放。

于 2010-03-15T16:14:01.863 回答
0

位于堆栈上的所有内容都被垃圾收集器视为全局根。所以,是的,你绝对可以说堆栈是“垃圾收集”。

于 2010-03-15T16:23:38.630 回答
0

No one, data is pushed and popped from stack as you have inner variables in methods, during method calls, etc. You don't need to care about this.

于 2010-03-15T13:48:51.617 回答
0

不,堆栈不是 Java 中的垃圾收集器。每个线程都有自己的堆栈并包含:

  1. 方法特定的值(它们是短暂的)和
  2. 对对象的引用,在堆上创建,并被方法引用

对于每个方法调用,这些值作为堆栈帧推送到堆栈。由于堆栈遵循“后进先出”顺序,因此在每个方法调用结束时,都会弹出包含所有方法特定数据和对象引用(如果有)的每个堆栈帧。

因此,一旦方法/程序超出范围,堆栈中的数据就会自动清理。

于 2016-02-23T10:44:13.110 回答