alloca 和 ObjectiveC 垃圾收集器
Posted
技术标签:
【中文标题】alloca 和 ObjectiveC 垃圾收集器【英文标题】:alloca and ObjectiveC Garbage Collector 【发布时间】:2010-12-23 05:47:21 【问题描述】:在启用 GC 的目标 C 项目中,我在堆栈上分配可变大小的数组,如下所示:
MaValue *myStack = alloca((sizeof(id) * someLength));
(我想这样做的原因并不重要:) 然后,在一个循环中,我在 myStack 上/从 myStack 上推送和弹出内容。我压入堆栈的一些东西是其他任何地方都没有引用的新对象。
我的直觉告诉我,目标 C 垃圾收集器不知道这些指针,因此会收集新的(否则未引用的)对象。这种信念的一部分来自这样一种想法,即目标 C GC 并不是真正保守的,而是“知道它的指针”(例如,通过堆栈映射)。
但是,在我所有的实验中(插入 [[NSGarbageCollector defaultCollector] collectExhaustively] 调用)我没有收集这些对象——这很好,但出乎意料。看起来,GC 正在扫描整个堆栈,例如,保守地假设一个恰好具有有效指针值的整数实际上是一个指针。
正确吗?还是我错过了什么?
【问题讨论】:
MaValue
是 Objective-C 的类类型吗?如果是这样,您应该将其声明为MaValue **myStack = ...
,即指向指针的指针,因为它是指向对象的指针数组。每个对象实例仍然需要在堆上分配,此时 GC 接管内存管理。堆栈上不能有 Objective-C 对象实例,只有指向它们的指针。
【参考方案1】:
它的行为正确。
虽然收集器 [尽可能] 准确地扫描堆,因为每个类都有一个布局,并且只扫描引用对象或使用 __strong 的槽,但必须保守地扫描堆栈。必须扫描堆栈上每个指针大小和指针对齐的槽以查找引用。
因此,您的 alloca() 将堆栈指针向下颠簸,并且收集器会扫描所有堆栈指针。您可能应该抛出一个断言以确保分配的空间是指针对齐的,否则行为是未定义的。
实际上,您根本不应该使用 alloca()。甚至手册页都说
alloca() 函数是机器和 编译器依赖;它的用途是 气馁。
改为使用NSAllocateCollectable()
分配扫描的堆空间块。除非您谈论的是许多分配与其他操作,否则开销应该是最小的。此外,您不再冒 [几乎同样大] 超出线程最大堆栈大小的风险(这并不大,并且会根据您正在运行的线程及其分配方式而变化。
【讨论】:
以上是关于alloca 和 ObjectiveC 垃圾收集器的主要内容,如果未能解决你的问题,请参考以下文章