垃圾收集器会收集堆内存、栈内存还是两者都收集?

17

我读了很多关于垃圾回收的文章,几乎所有文章都是讲堆内存。所以我的问题是,“垃圾回收是回收栈内存、堆内存还是两者都回收”。


重复。https://dev59.com/QkzSa4cB1Zd3GeqPlEIS - XpiritO
9个回答

22

它收集堆内存。通常情况下,当执行路径到达作用域的结尾时,栈内存会被自动收集。例如:

void fun()
{
  int n; // reservation on the stack as part of the activation record
  ...
} // returning the stack pointer to where it was before entering the scope

实际上,在像 C++ 这样的语言中,栈分配的变量被称为 auto 变量。


12

堆内存。

垃圾回收是一种释放不再使用的内存的方法。有时,“不再使用的”部分可能比较棘手。对于栈来说,一旦函数返回,我们可以(除了程序员错误)放心地认为本地变量不再被使用,因此它们会在几乎所有语言/运行时自动释放。


7

堆栈被称为“堆栈”,正是因为它是一个使用“堆栈策略”(也称为LIFO,即后进先出)进行管理的内存区域。如果不按照“堆栈方式”在堆栈上分配内存,则不会称之为堆栈而是堆。

垃圾回收是为了解决在堆上分配内存(即不能预测哪些部分将首先释放)的问题而发明的。 GC用于内存分配问题,其中堆栈管理不足以满足要求。


3

栈是后进先出的,因此不需要进行垃圾回收。

--已更正-- 哎呀!


你肯定是指后进先出。 - Alex Stoddard
2
是的,但不要叫我雪莉。 - Steven Sudit

1

除非您使用的是我们都不知道的分析器,否则堆栈将是主要问题。这是因为大多数人只是按照一个备受赞誉的工具所说的去反应。请看完这篇文章,您会发现大多数指出静态分配内存错误的分析工具通常是正确的。性能分析应该超越简单的泄漏和垃圾收集。

让我以 C 语言为例:

#include <stdlib.h>
#include <string.h>

int main(void)
{
   char *am_i_leaking;

   am_i_leaking = strdup("Now, that's subjective!");

   return 0;
}

如果运行此程序的操作系统不自动回收堆,则会出现问题。我想不到现代操作系统不会这样做,实际上都在使用。
现在让我们来看看这个:
char *foo(void)
{
    static char bar[1024];
    memset(bar, 0, sizeof(bar));
    snprintf(bar, sizeof(bar -1), "Do wa diddy diddy dum diddy do");

    return bar;
}

你的编译器如何分配内存,这取决于你的编译器。如果你使用它并且可以调整结果,那么你可能有一个有问题的编译器。然而,如果我有100个线程同时进入该函数,那么结果肯定是垃圾,除非我的编译器神奇地弄清楚了我想要什么,并引入了互斥或动态分配,而我不必担心它,此时我们又回到了堆分析。

简而言之,在我们的生命周期中,垃圾收集与堆有关。未来会有一些人尝试着去处理栈并尝试“优化”事情,然后计算这种努力成为一种被一群CEO所需求的解释性语言。

这并不意味着忽略内存错误是一件好事,无论存储器是什么。


1

栈是您的方法参数和本地变量所在的位置。如果您离开该方法,则堆栈指针会自动递减(或递增,具体取决于特定实现)。这对大多数编程语言都是正确的。

相比之下,垃圾回收仅在堆上工作。


1

至少在Java中,堆栈会在离开该堆栈帧时自动释放,因此无需垃圾回收。

我是一名Java程序员,所以我没有这个问题,但实际上在C++中,(据我听说)你必须小心处理这个问题,因为你可以在堆栈上分配对象,而当你离开该堆栈帧时,对象将被释放,你不能再使用它等。


1
在C++中,存储在堆栈上的对象在函数返回时会自动释放。但是,您可以在堆上分配一个对象,并将该对象的指针存储在堆栈上;然后当函数返回并离开该堆栈帧时,您会失去指针的唯一副本,从而泄漏对象。如果C++内置了垃圾回收(它是可选的),这将不是问题。 - dave4420
@Dave Hinton:你可以将指向当前堆栈帧分配的对象的指针传递到另一个堆栈帧,并感到惊讶,对吗?没有? - Enno Shioji
1
在Java中,没有对象存储在堆栈上;它只保留对对象的引用。所有实际对象都在堆中。在Java方法结束后,引用丢失,但堆中的对象仍然存在。在C++中,对象可以直接放置在堆栈上,并且该内存区域在函数结束后无效。 - Kevin Panko

1
Java中的垃圾回收器仅在堆内存而非栈内存上运行,这是由栈的主要原则决定的,即后进先出。这就解释了一切,也就是说,当函数作用域结束时,栈会自动清空。请保留HTML标签。

0

你没有引用任何特定的技术,但这种使用在各种编程语言中都很典型。

垃圾回收器仅在托管堆上工作。在单个进程中可能有多个堆,其中一些不会进行垃圾回收。

在堆栈上分配的变量在方法返回时被释放。垃圾回收器将使用这些变量来查找活动引用,但它不会回收内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接