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 垃圾收集器的主要内容,如果未能解决你的问题,请参考以下文章

2垃圾回收算法(标记清除算法复制算法标记整理算法和分代收集算法),各种垃圾收集器讲解(学习笔记)

6.GC垃圾回收算法和垃圾收集器的关系

CMS垃圾收集器和G1垃圾收集器

5种JVM垃圾收集器特点和8种JVM内存溢出原因

5种JVM垃圾收集器特点和8种JVM内存溢出原因

CMS垃圾收集器——重新标记和浮动垃圾的思考