在Java中收集堆栈垃圾?

堆内存是垃圾收集在Java中。

是否收集堆栈垃圾?

堆栈内存是如何回收的?

堆栈中的内存包含方法参数和局部variables(准确地说:对于原始types的对象和variables本身的引用)。 如果你离开这个方法,这将被自动删除。 如果variables是引用(对象),则对象本身在堆上,并由垃圾收集器处理。

所以堆栈并不像垃圾堆那样被垃圾收集,但是堆栈本身就是一种自动的内存pipe理(在垃圾收集之前)。

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

堆栈不是垃圾收集在Java中。

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

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

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

我们称之为堆栈的是方法激活上下文的积累:对于每个被调用的方法,这是包含方法参数,局部variables,调用方法的上下文的隐藏指针和保存指令的槽的概念结构指针。 激活上下文不能从Java语言本身访问。 当方法退出( return或由于抛出的exception)时,上下文变得毫无用处。 恰巧当方法A调用方法B时,保证当A重新获得控制权时,B的上下文变得没有用处。 这意味着B的上下文的生命周期是A的上下文生命周期的子范围。因此,激活上下文(对于给定的线程)可以用LIFO(“后进先出”)规则来分配。 用简单的话来说,一个堆栈:一个新的激活上下文被推到上下文的堆栈之上,上面的上下文将被首先处理。

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

现在,没有任何东西可以阻止JVM实现,例如,在堆中分配激活上下文并让GC收集它们。 这通常不会在Java虚拟机中完成,因为堆栈分配速度更快。 但其他一些语言需要做这样的事情,尤其是那些在继续使用GC的情况下继续使用(例如Scheme和call-with-current-continuation函数),因为这样的游戏会破坏上面解释的LIFO规则。

内存的堆栈部分就像一个“堆栈”。 我知道这听起来很糟糕,但这正是它的工作原理。 数据被添加到顶部,在彼此之上( pushed onto the stack ),并在程序运行时自动从顶部( popped off the stack )移除。 这不是垃圾回收 – 而且也不需要,因为一旦数据从堆栈中popup,内存就会自动回收。 当我说回收的时候,我并不是说它会被解除分配 – 只是因为数据被popup,堆栈内存中下一个数据将被存储的位置会减less。

当然,这并不是说你不需要担心堆栈。 如果你多次运行一个recursion函数,它最终将耗尽所有的堆栈空间。 如果您调用多个函数,尤其是如果它们具有许多参数和/或局部variables时,也是如此。

但底线是堆栈的内存被使用和回收作为function自动进入和离开范围。 所以在程序执行结束时,所有的堆栈内存都将被释放,然后释放回操作系统。

如果引用堆栈中使用的内存,则不会收集垃圾。
Java虚拟机使用明确的字节码指令来保留和释放堆栈中的内存,这些指令是由编译器生成的,并pipe理堆栈上的int,boolean,double和object-references等基元的生命周期。
已经有计划实现所谓的尾部调用优化,一旦知道它们不再使用,就会从栈中移除一些条目,但是我不知道任何已经支持这个的jvm。
所以没有没有垃圾收集堆栈本身,只有编译器生成推和popup指令来pipe理内存使用。

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

Java中的所有对象都分配在堆上。 (至less就规范而言,如果实际执行的行为就像在堆上一样,实际实现可能会将它们分配到堆栈上。)

究竟什么是可收集的有点微妙。 如果对象的唯一引用位于单个堆栈框架中,并且可以显示引用不会再次使用,则可以收集该对象。 如果该对象仅用于读取一个字段,那么该字段读取可能会被优化,并且收集的对象比您期望的要早。

这通常不重要,除非你正在使用finalisers(或推测Reference s)。 在这种情况下,您应该小心并使用locking/易失性来强制执行happens-before关系。

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

位于堆栈上的所有东西都被垃圾收集器视为全局根。 所以,是的,你一定可以说堆栈是“垃圾收集”。

没有人会从堆栈中压入和popup数据,因为在方法调用等方法中有内部variables。您不需要关心这一点。

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

  1. 方法特定的值(这是短暂的)和
  2. 对在堆上创build的对象的引用,并且正在被方法引用

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

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

Interesting Posts