与其在运行时定期运行垃圾检测,我们为什么不让编译器在适当的地方自动插入 free() 呢?这样,我们在编译时只需付出一次代价。

编译器知道变量超出范围或重新分配给不同对象的位置。因此,它然后可以找出对象是否不再可达,并在那里自动插入 free() 。

不能吗?为什么?

如果是因为多线程,那么我们可以用单线程/绿色线程语言来做吗?

最佳答案



当然可以 - 对于变量。但是您没有清除变量 - 您清除了它们指向的内存。并且仅仅因为变量超出范围,并不意味着指向的内存不再可达。

例如:

y = ...
{
  x = new X();
  if (todayIsTuesday()) {
    y = x;
  }
} // x just went out of scope

您无法在编译时决定是否应该在该段的最后一行释放 x 指向的内存,因为这取决于运行该代码时是一周中的哪一天。

所以为了解决这个问题,这个决定必须委托(delegate)给运行时,通过插入适当的逻辑,例如:
Y* y = ...
{
  X* mem = new X();
  X* x = mem;
  markPointer(&x, mem);
  if (todayIsTuesday()) {
    y = x;
    markPointer(&y, mem);
  }
  markNoLongerPointer(&x, mem);
} // x just went out of scope
markNoLongerPointer() 清除作为第二个参数给出的内存,如果其内部维护的数据结构告诉它 x 是对该内存的唯一引用......换句话说,这是引用计数逻辑的粗略起点。

编译器当然可以在编译后的代码中添加这样的引用计数逻辑,有些人会,但正如其他人提到的,引用计数有一些缺点:高开销,循环问题,再加上它有时会在不方便的时候导致明显的暂停,当只有对大型数据结构的根的引用超出范围。不过,有一些方法可以解决其中一些缺点,但这超出了本答案的范围:-)

关于compiler-construction - 为什么要垃圾回收?为什么编译器不自动插入 free() 呢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34915554/

10-13 06:30
查看更多