alloca 和 ObjectiveC 垃圾收集器

发布于 2024-08-14 07:42:08 字数 510 浏览 8 评论 0原文

在启用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

好倦 2024-08-21 07:42:08

它的行为正确。

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

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

实际上,你根本不应该使用 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

The alloca() function is machine and
compiler dependent; its use is
discouraged.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文