垃圾回收

8

我无法理解垃圾回收方面的一些问题。

首先,数据是如何分配空间的?即栈还是堆(据我所知,所有静态或全局变量都在栈上分配空间,而局部变量则在堆上分配空间)。

其次,GC运行在栈或堆上的数据上吗?例如,像标记/清除这样的GC算法会将堆栈上的数据称为根集,然后通过检查哪些堆上的变量引用根集来映射到所有可达的变量。

如果程序没有全局变量怎么办?那么算法如何工作呢?

问候, darkie


2
你是在询问特定的平台/垃圾收集器吗?请编辑您的标签和/或问题以更具体。 - Jay
一般来说,这是关于垃圾回收的讨论。参考维基百科链接:http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29 - name_masked
6个回答

11

要澄清你在询问哪个平台的GC可能会有所帮助- JVM,CLR,Lisp等。 话虽如此:

首先退后一步,某些局部变量通常在堆栈上分配。 具体规则可能因语言而异。 以C#为例,仅对于局部值类型和方法参数存储在堆栈上。 因此,在C#中,foo将在堆栈上分配:

public function bar() { 
    int foo = 2;
    ...
}

动态分配的变量使用堆中的内存。这应该是直观的,否则堆栈将不得不在每次调用new时动态增长。此外,这意味着这些变量只能作为局部变量在分配它们的本地函数中使用,这当然是不正确的,因为我们可以有(例如)类成员变量。所以再举一个C#的例子,在以下情况下,result在堆上分配:

public class MyInt
{         
    public int MyValue;
}

...
MyInt result = new MyInt();
result.MyValue = foo + 40;
...

考虑到这一点,位于上的内存是垃圾回收的。栈上的内存不需要GC,因为当当前函数返回时,该内存将被回收。在高层次上,GC算法通过跟踪动态分配在堆上的所有对象来工作。一旦通过new进行分配,对象将被GC跟踪,并在其超出范围且没有更多引用时进行回收。


“只存储值类型在堆栈上”这个说法并不严谨。引用《C# 深入》第 52 页:“一个变量的值存在于它被声明的位置——所以如果你有一个包含 int 类型实例变量的类,那么这个变量对于给定对象的值将总是存在于对象其余数据所在的堆上...只有本地变量和方法参数存在于堆栈上...” - duffymo
1
是的,我的意思是仅存储在堆栈上的值类型本地变量。我会更新答案以使其更清晰。 - Justin Ethier
@Justin:当你说:“这应该是直观的,否则堆栈每次调用新函数时都必须动态增长。此外,这意味着这些变量只能在分配它们的本地函数中使用,这显然是不正确的。” ...你是指仅适用于C#吗? 这是用Java编写的代码片段: public class StringCheck { public static void main(String[] args) { callingOne(); callingTwo(); } public static void callingOne() { Integer temp = new Integer("1"); } - name_masked
不是的,这取决于上下文。在你的例子中,temp是一个局部变量,因此只能从callingOne访问。要使它在两个地方都可访问,你需要将其作为类成员变量(并使用非静态方法),或将其作为参数传递给callingTwo。 - Justin Ethier
此外,本地值将分配在寄存器中,只有在必要时才会溢出到堆栈。 - J D
显示剩余2条评论

2

嗯,我无法访问书籍的内容。不管怎样,谢谢。 - name_masked

2
首先,数据是如何分配空间的? 即栈或堆(据我所知,所有静态或全局变量都分配在栈上,局部变量分配在堆上)。
不,栈变量是方法调用和局部变量。当方法被调用时创建一个栈帧,返回时弹出。
Java和C#中的内存通过调用“new”在堆上分配。
其次,GC在堆栈上运行吗? 即像Mark/Sweep这样的GC算法会将栈上的数据视为根集吗?然后通过检查哪些在堆上的变量引用根集来映射所有可达变量在堆上的位置。
GC用于堆。
现在Java和.NET GC都使用分代模型,Mark and sweep不被认为是尖端的GC算法。
如果程序没有全局变量怎么办?那么算法怎么工作?
在像Java和C#这样的语言中,“全局变量”是什么意思?对象图的根是任意的,我承认我不知道它是如何选择的。

非常感谢,这对我解释了很多。 - name_masked

1

阅读这篇文章。它是关于单处理器垃圾回收技术的一份非常好的调查报告。它将为您提供有关GC的基本理解和术语。然后,跟进Jones和Lins的书籍“Garbage Collection:Algorithms for Automatic Dynamic Memory Management”。与我上面指向的调查文章相反,该书在Web上不免费提供;但它是值得购买的。


1

0

您可能会发现内存管理参考中的垃圾回收的简短摘要很有用。

最终,垃圾回收必须从处理器的寄存器开始,因为处理器无法访问的任何对象都可以被回收利用。根据语言和运行时系统,假定线程的堆栈和寄存器以及“全局变量”是可达的是有意义的。

堆栈可能会给您提供本地变量。因此,在简单的GC中,您可以通过扫描线程上下文、它们的堆栈和全局变量来开始。但这在每种情况下都不一定正确。有些语言不使用堆栈或没有全局变量。此外,GC可以使用屏障,以便它们不必每次都查看每个堆栈或全局变量。一些专门的硬件,例如Symbolics Lisp Machine,在寄存器上也有屏障!


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