alloca 和 ObjectiveC 垃圾收集器
在启用 GC 的目标 C 项目中,我在堆栈上分配一个可变大小的数组,如下所示:(
MaValue *myStack = alloca((sizeof(id) * someLength));
我想这样做的原因并不重要:) 然后,在一个循环中,我将内容推送到 myStack 或从 myStack 中弹出内容。我推入堆栈的一些内容是未从其他任何地方引用的新对象。
我的直觉告诉我,目标 C 垃圾收集器不知道这些指针,因此会收集新的(否则未引用的)对象。这种信念的一部分来自于这样的想法:目标 C GC 并不是真正保守的,而是“知道它的指针”(例如,通过堆栈映射)。
然而,在我所有的实验中(插入 [[NSGarbageCollector defaultCollector]collectExhaustively] 调用)我没有收集这些对象 - 这很好,但出乎意料。因此,GC 似乎正在扫描整个堆栈,并且,例如,保守地假设恰好具有有效指针值的整数确实是一个指针。
这是正确的吗?或者我错过了什么?
In an objective C project with GC enabled, I am allocating an array of variable size on the stack like this:
MaValue *myStack = alloca((sizeof(id) * someLength));
(The reason why I want to do this is not important:)
Then, within a loop, I push and pop stuff on/from myStack. Some of the things I push onto the stack are new objects that are not referenced from anywhere else.
My gut feeling tells me, that the objective C garbage collector doesn't know about those pointers and therefore would collect the new (otherwise unreferenced) objects. Part of that believe comes from the thought, that the objective C GC isn't really conservative but "knows its pointers" (e.g., through a stack map).
However, in all my experiments (inserting [[NSGarbageCollector defaultCollector] collectExhaustively] calls) I didn't get those objects to be collected – which is good, but unexpected. So it seems, that the GC is scanning the whole stack and, for example, conservatively assumes an integer that happens to have the value of a valid pointer to really be a pointer.
Is that correct? Or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它的行为正确。
虽然收集器[尽可能多]地精确扫描堆,因为每个类都有一个布局,并且只扫描引用对象或使用 __strong 的槽,但必须保守地扫描堆栈。必须扫描堆栈上每个指针大小和指针对齐的槽以查找引用。
因此,您的 alloca() 会将堆栈指针向下移动,收集器会扫描所有内容。您可能应该抛出一个断言以确保分配的空间是指针对齐的,否则行为是未定义的。
实际上,你根本不应该使用 alloca() 。甚至手册页也说
相反,使用 NSAllocateCollectable() 来分配扫描的堆空间块。除非您正在谈论与其他操作相比的许多分配,否则开销应该很小。此外,您不再面临[几乎一样大]超过线程最大堆栈大小的风险(该堆栈大小并不大,并且会根据您运行的线程及其分配方式而变化。
It is behaving correctly.
While the collector scans the heap exactly [as much as possible] in that each class has a layout and only the slots that refer to objects or use __strong are scanned, the stack must be scanned conservatively. Every pointer sized and pointer aligned slot on the stack must be scanned for references.
Thus, your alloca() bumps the stack pointer down and the collector scans all of it. You should probably throw in an assert to make sure the alloca'd space is pointer aligned as the behavior is otherwise undefined.
Actually, you really shouldn't use alloca() at all. Even the man page says
Instead, use
NSAllocateCollectable()
to allocate a scanned chunk of heap space. Unless you are talking about many allocations vs. your other operations, the overhead should be minimal. Furthermore, you no longer run [nearly as great] a risk of exceeding the maximum stack size of a thread (which isn't large and changes depending on which thread you are running on and how it is allocated.