在启用GC的目标C项目中,我在堆栈上分配一个可变大小的数组,如下所示:
MaValue *myStack = alloca((sizeof(id) * someLength));
(我之所以这样做并不重要:) 然后,在循环中,我在myStack上推送内容。我推入堆栈的一些东西是新对象,不能从其他任何地方引用。
我的直觉告诉我,目标C垃圾收集器不知道那些指针,因此会收集新的(否则未引用的)对象。部分相信来自于这个想法,即目标C GC并不是真正保守而是“知道它的指针”(例如,通过堆栈图)。
然而,在我的所有实验中(插入[[NSGarbageCollector defaultCollector] collectExhaustively]调用)我没有得到那些要收集的对象 - 这很好但是出乎意料。所以看起来,GC正在扫描整个堆栈,例如,保守地假设一个整数碰巧有一个有效指针的值真的是一个指针。
这是对的吗?或者我错过了什么?
答案 0 :(得分:3)
行为正确。
虽然收集器尽可能精确地扫描堆,因为每个类都有一个布局,并且只扫描引用对象或使用__strong的槽,但必须保守地扫描堆栈。必须扫描堆栈上的每个指针大小和指针对齐的插槽以供参考。
因此,你的alloca()会将堆栈指针向下碰撞,而收集器会扫描所有堆栈指针。你可能应该抛出一个断言来确保alloca'd空间是指针对齐的,否则行为是未定义的。
实际上,你真的不应该使用alloca()。即使是手册页也说
alloca()函数是机器和 编译器依赖;它的用途是 气馁。
相反,使用NSAllocateCollectable()
分配扫描的堆空间块。除非您在谈论许多分配与其他操作,否则开销应该是最小的。此外,您不再运行[几乎同样大]超过线程最大堆栈大小的风险(这不大并且根据您运行的线程及其分配方式而变化。