我无法理解垃圾回收方面的一些问题。
首先,数据是如何分配空间的?即栈还是堆(据我所知,所有静态或全局变量都在栈上分配空间,而局部变量则在堆上分配空间)。
其次,GC运行在栈或堆上的数据上吗?例如,像标记/清除这样的GC算法会将堆栈上的数据称为根集,然后通过检查哪些堆上的变量引用根集来映射到所有可达的变量。
如果程序没有全局变量怎么办?那么算法如何工作呢?
问候, darkie
我无法理解垃圾回收方面的一些问题。
首先,数据是如何分配空间的?即栈还是堆(据我所知,所有静态或全局变量都在栈上分配空间,而局部变量则在堆上分配空间)。
其次,GC运行在栈或堆上的数据上吗?例如,像标记/清除这样的GC算法会将堆栈上的数据称为根集,然后通过检查哪些堆上的变量引用根集来映射到所有可达的变量。
如果程序没有全局变量怎么办?那么算法如何工作呢?
问候, darkie
要澄清你在询问哪个平台的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跟踪,并在其超出范围且没有更多引用时进行回收。
阅读这篇文章。它是关于单处理器垃圾回收技术的一份非常好的调查报告。它将为您提供有关GC的基本理解和术语。然后,跟进Jones和Lins的书籍“Garbage Collection:Algorithms for Automatic Dynamic Memory Management”。与我上面指向的调查文章相反,该书在Web上不免费提供;但它是值得购买的。
您可能会发现内存管理参考中的垃圾回收的简短摘要很有用。
最终,垃圾回收必须从处理器的寄存器开始,因为处理器无法访问的任何对象都可以被回收利用。根据语言和运行时系统,假定线程的堆栈和寄存器以及“全局变量”是可达的是有意义的。
堆栈可能会给您提供本地变量。因此,在简单的GC中,您可以通过扫描线程上下文、它们的堆栈和全局变量来开始。但这在每种情况下都不一定正确。有些语言不使用堆栈或没有全局变量。此外,GC可以使用屏障,以便它们不必每次都查看每个堆栈或全局变量。一些专门的硬件,例如Symbolics Lisp Machine,在寄存器上也有屏障!