objective-c - 什么时候在 Objective-C 代码中直接使用 objc_memmove_collectable?

标签 objective-c garbage-collection

在头文件和文档中寻找其他内容时,我最近在 <objc/objc-auto.h> 中发现了以下函数原型(prototype):

void *objc_memmove_collectable(void *dst, const void *src, size_t size);

它位于一组函数的中间,在注释“写屏障。由编译器使用”之后。这些函数用于通知垃圾收集器它管理的内存已被修改,因此它可以扫描引用而不是意外地回收应该由它不知道的强引用作为根的内存。我知道这样使用 __strong appropriately 几乎总是会导致编译器插入正确的函数,但我也听说 Apple 工程师说在极少数情况下你必须直接调用这些函数。 (我相信当文件没有被编译为 Objective-C 时,例如写入 GC 管理的内存的 C 代码,但我不是肯定的。)

也就是说,Apple 的 Objective-C Runtime Release Notes for Mac OS X v10.5文件对这个功能作了如下说明:(第一个标题下的最后一段)

"When copying memory in bulk into a garbage collected block you must use the API objc_memmove_collectable(void *dst, const void *src, size_t size)."

该功能似乎旨在将项目从非 GC 内存移动到 GC 内存,并且电子邮件讨论文件似乎表明其目的是仅为大块副本触发单个写屏障。 (例如,1000 次单独的写入,每次写入都有一个写屏障,而 1 个批量复制,整个内存区域只有一个写入屏障。)这是一个必须使用它的例子,但是文档没有说明什么时候不应该(或不需要)使用它。

例如,我有一 block 内存是用 NSAllocateCollectable() 分配的和 NSScannedOption ,我将它用作动态扩展的循环缓冲区。如果缓冲区已满,我会使用 NSReallocateCollectable() 将其大小加倍和 NSScannedOption .环绕的部分(在数组中的第一个插槽和缓冲区中的最后一个对象之间)被复制/移动到数组后半部分的开头。然后我bzero()从中复制数据的插槽,以避免移动的对象过度生根。 (请参阅 this file 中的第 460-467 行。是的,代码按原样工作 — 它经过了全面的单元测试,自从我之前添加了 __strong 属性以来,我还没有看到任何崩溃。)

问题:

  • 什么时候需要用objc_memmove_collectable()而不是 memmove()memcpy()
  • 例如,如果源和目标都是 GC 管理的内存怎么办? (我的内存被声明为 __strong id *array; 所以我猜编译器插入了屏障。)
  • 如果没有必要,使用它会有助于/阻碍 GC 性能吗? (例如,它是否持有任何类型的锁,或帮助 GC 避免必须手动扫描?)它被认为是好/差的风格吗?

编辑memcpymemmove根本不与 GC 交互,我想知道为什么我没有看到从我下面收集的内存发生任何崩溃。在这一点上我最好的猜测是自bzero也不告诉 GC 任何信息,收集器直到下一次扫描整个内存块时才会发现已归零的内存和移动的数据。如果收集器仍在将现在归零的引用计为根,并且尚未计入新的内存位置,则可以解释为什么不会过早收集这些值。这听起来对吗?

最佳答案

我相信@bbum 会给出一个更具解释性和明确性的答案,但这是我的理解,可能不是 100% 准确。

如标题注释所述,每当您将数据批量写入(即使用 memcpymemmove,而不是使用 =)到已扫描、GC 分配的缓冲区,您应该始终使用objc_memmove_collectable 来创建写屏障。数据来源无关紧要。 memcpy 没有智慧知道您是否从扫描的、GC 分配的内存复制到其他扫描的、GC 分配的内存。

我不确定在没有写屏障的情况下 GC 是否会错误地运行,但它肯定会表现得更好。写障碍是对收集器的提示,说‘嘿!我可能在这里写了一个指针。你可以检查一下吗?'。如果没有这些,收集器将被迫一直进行全面扫描。

此外,单个 objc_memmove_collectable() 比一堆隐式写屏障的 = 赋值要高效得多,即使您完全忽略实际的成本写内存。只做了一个写屏障而不是N个。

关于objective-c - 什么时候在 Objective-C 代码中直接使用 objc_memmove_collectable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2235510/

相关文章:

objective-c - 直接释放一个对象

objective-c - 在后台安排 LocalNotifications 时应用卡住

ios - 在 iOS 的不同设备上为同一个项目使用不同的文件?

java - 如何解读Java G1 GC暂停时间原因

java - Java7 垃圾优先收集器如何工作?

java - 为什么年轻代GC时老年代似乎被清除了

ios - 取消选中 UITableview 中的单元格时,如何从数组中删除数据?

iOS : Remove a Persistent Storage in a Multithreading CoreData Implementation

objective-c - 如何编写 Objective-C 便捷构造函数

c# - IsDisposed 是如何工作的?