1

在启用 GC 的目标 C 项目中,我在堆栈上分配一个可变大小的数组,如下所示:

MaValue *myStack = alloca((sizeof(id) * someLength));

(我想这样做的原因并不重要:)然后,在一个循环中,我在 myStack 上/从 myStack 上推送和弹出内容。我压入堆栈的一些东西是没有从其他任何地方引用的新对象。

我的直觉告诉我,目标 C 垃圾收集器不知道这些指针,因此会收集新的(否则未引用的)对象。这种信念的一部分来自这样一种想法,即目标 C GC 并不是真正保守的,而是“知道它的指针”(例如,通过堆栈映射)。

然而,在我所有的实验中(插入 [[NSGarbageCollector defaultCollector] collectExhaustively] 调用)我没有收集到这些对象——这很好,但出乎意料。所以看起来,GC 正在扫描整个堆栈,例如,保守地假设一个恰好具有有效指针值的整数实际上是一个指针。

那是对的吗?还是我错过了什么?

4

1 回答 1

3

它的行为正确。

虽然收集器 [尽可能] 准确地扫描堆,因为每个类都有一个布局,并且只扫描引用对象或使用 __strong 的槽,但必须保守地扫描堆栈。必须扫描堆栈上每个指针大小和指针对齐的插槽以查找引用。

因此,您的 alloca() 将堆栈指针向下颠簸,并且收集器会扫描所有堆栈指针。您可能应该抛出一个断言以确保分配的空间是指针对齐的,否则行为是未定义的。

实际上,您根本不应该使用 alloca() 。甚至手册页都说

alloca() 函数依赖于机器和编译器;不鼓励使用它。

相反,用于NSAllocateCollectable()分配扫描的堆空间块。除非您在谈论许多分配与您的其他操作,否则开销应该是最小的。此外,您不再冒 [几乎同样大] 超出线程最大堆栈大小的风险(这并不大,并且会根据您正在运行的线程及其分配方式而变化。

于 2009-12-04T16:41:56.407 回答