堆栈垃圾是用Java收集的吗?

gir*_*iri 55 java garbage-collection gc-roots

堆内存是用Java收集的.

堆栈垃圾也收集了吗?

如何回收堆栈内存?

Mne*_*nth 37

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

因此,堆栈不是以与堆相同的方式进行垃圾收集,而是堆栈是一种自动内存管理形式(在垃圾收集之前).

Thomas Pornin给出了一个更详细的答案,请查看更多细节.


Joa*_*uer 28

堆栈不是用Java收集的垃圾.

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

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

  • 确切地说,堆栈不包含任何可以被垃圾收集的东西.它包含的唯一内容是对基元类型的对象和值的引用.唯一受垃圾收集影响的是对象.请注意对象与对象的引用之间的区别. (11认同)
  • 如果“他们”的意思是“局部变量”,那么在堆栈上。如果你的意思是对象,那么在堆上。并且可能存在引用对象(堆)的局部变量(堆栈)。 (2认同)

Tho*_*nin 14

堆栈可能是垃圾收集.但是,在大多数JVM实现中,它被处理为"堆栈",根据定义,它排除了垃圾收集.

我们称之为堆栈的是方法激活上下文的累积:对于每个被调用的方法,这是概念结构,其包含方法参数,局部变量,指向调用方法的上下文的隐藏指针,以及用于保存指令的槽.指针.激活上下文不能从Java语言本身访问.当方法退出时(带有return或因为抛出的异常),上下文变得无用.碰巧当方法A调用方法B时,可以保证当A重新获得控制时,B的上下文变得无用.这意味着B的上下文的生存期是A的上下文生命周期的子范围.因此,激活上下文(对于给定的线程)可以使用LIFO("后进先出")规则进行分配.简单来说,就是一个堆栈:一个新的激活上下文被推送到一堆上下文之上,而顶层的上下文将是第一个被处理掉的.

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

现在没有什么能阻止JVM实现做其他事情,例如在堆中分配激活上下文并由GC收集它们.这通常不在Java虚拟机中完成,因为堆栈分配更快.但是其他一些语言需要做这样的事情,最明显的是那些玩延续,同时依然采用了GC(如计划和它的call-with-current-continuation功能),因为这类游戏打破LIFO规则如上所述.


Mik*_*scu 8

内存的堆栈部分就像"堆栈"一样工作.我知道这听起来很糟糕,但这正是它的工作原理.数据被添加到顶部,彼此重叠(pushed onto the stack)并popped off the stack在程序运行时自动从顶部()中删除.它不是垃圾收集 - 并且它不需要是因为一旦数据从堆栈弹出就自动回收内存.当我说回收时,我并不是说它被取消分配 - 只是当数据被弹出时,堆栈存储器中存储下一个数据的位置会减少.

当然,这并不是说你根本不需要担心堆栈.如果多次运行递归函数,它最终将耗尽所有堆栈空间.如果调用许多函数,则相同,特别是如果它们有许多参数和/或局部变量.

但最重要的是,当函数自动进入和离开范围时,使用并回收堆栈的内存.因此,在程序执行结束时,所有堆栈内存都将是空闲的,然后释放回操作系统.


jos*_*efx 5

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

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