我阅读了很多关于垃圾收集的文章,几乎所有文章都讲述了堆内存。所以我的问题是“垃圾收集收集堆栈内存或堆内存或两者”。
9 回答
它收集堆内存。通常,当执行路径到达作用域的末尾时,会自动收集堆栈内存。例如:
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
变量。
堆内存。
垃圾收集是一种释放不再使用的内存的方法。有时“不再使用”部分很棘手。有了堆栈,只要函数返回,我们就可以确信(除了程序员错误)局部变量不再被使用,因此它们在几乎每种语言/运行时都会自动释放。
堆栈之所以称为“堆栈”,正是因为它是一个由“堆栈策略”(即 LIFO(后进先出))管理的内存区域。如果堆栈上的分配不是以“堆栈方式”完成的,它就不会被称为堆栈而是堆。
垃圾收集的发明是为了解决在堆上分配东西的问题,即这样你就无法预测哪些部分将首先被释放。GC 适用于堆栈管理不足的内存分配问题。
堆栈是后进先出的,因此不需要垃圾收集。
——更正了——呃!
除非您使用我们都不知道的分析器,否则堆是主要问题。这是因为大多数人只会对广受好评的工具告诉他们的任何内容做出反应。请到这篇文章的结尾,看看大多数指出静态分配内存错误的分析工具通常是正确的。分析应该超越简单的泄漏和垃圾收集。
让我给你一个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 需要的解释语言。
这并不意味着忽略内存错误是一件好事,无论存储是什么。
堆栈是您的方法参数和局部变量所在的位置。如果离开该方法,堆栈指针会自动递减(或根据具体实现递增)。对于大多数编程语言来说都是如此。
相比之下,垃圾收集仅适用于堆。
至少在 java 中,当您离开堆栈帧时,堆栈将自动取消分配,因此无需进行垃圾收集。
我是一名java程序员,所以我没有这个问题,但实际上在C++中,(我听说)你必须小心这个,因为你可以在堆栈上分配对象,你可以离开那个堆栈框架,该对象将被取消分配,您不能再使用它,等等。
您没有引用任何特定的技术,但是跨语言的使用是相当典型的。
垃圾收集器仅在托管堆上工作。单个进程中可能有多个堆,其中一些不是垃圾收集的。
当方法返回时,分配在堆栈上的变量会被释放。垃圾收集器将使用这些变量来查找实时引用,但它不会收集内存。
Java中的垃圾收集器仅适用于堆内存而不适用于堆栈内存,因为堆栈工作的主要原则是(后进先出)。这本身就说明了一切。即当函数范围的结尾是到达堆栈时自动为空。