objective-c - Apple 的 Objective-C 运行时如何在不降低性能的情况下进行多线程引用计数?

标签 objective-c multithreading performance memory-management reference-counting

所以我在读this article关于尝试从 Python 解释器中删除全局解释器锁 (GIL) 以提高多线程性能并看到一些有趣的东西。

事实证明,删除 GIL 实际上使事情变得更糟的地方之一是内存管理:

With free-threading, reference counting operations lose their thread-safety. Thus, the patch introduces a global reference-counting mutex lock along with atomic operations for updating the count. On Unix, locking is implemented using a standard pthread_mutex_t lock (wrapped inside a PyMutex structure) and the following functions...

...On Unix, it must be emphasized that simple reference count manipulation has been replaced by no fewer than three function calls, plus the overhead of the actual locking. It's far more expensive...

...Clearly fine-grained locking of reference counts is the major culprit behind the poor performance, but even if you take away the locking, the reference counting performance is still very sensitive to any kind of extra overhead (e.g., function call, etc.). In this case, the performance is still about twice as slow as Python with the GIL.

及以后:

Reference counting is a really lousy memory-management technique for free-threading. This was already widely known, but the performance numbers put a more concrete figure on it. This will definitely be the most challenging issue for anyone attempting a GIL removal patch.

所以问题是,如果引用计数对于线程来说如此糟糕,那么 Objective-C 是如何做到的呢?我编写过多线程 Objective-C 应用程序,并没有注意到内存管理的开销很大。他们在做别的事吗?像某种按对象锁而不是全局锁? Objective-C 的引用计数实际上在技术上对线程不安全吗?我不是并发专家,无法真正推测很多,但我很想知道。

最佳答案

存在开销,并且在极少数情况下(例如,微基准测试;),无论是否进行了优化(其中有很多),它都可能很重要。不过,正常情况针对对象引用计数的非竞争操作进行了优化。

So the question is, if reference counting is so lousy for threading, how does Objective-C do it?

有多个锁在起作用,实际上,对任何给定对象的保留/释放会为该对象选择一个随机锁(但始终是相同的锁)。因此,减少了锁争用,同时不需要每个对象一个锁。

(以及 Catfish_man 所说的;一些类将实现自己的引用计数方案以使用特定于类的锁定原语来避免争用和/或针对其特定需求进行优化。)

实现细节比较复杂。

Is Objectice-C's reference counting actually technically unsafe with threads?

不——它在线程方面是安全的。

实际上,与其他操作相比,典型代码很少会调用retainrelease。因此,即使这些代码路径上存在大量开销,它也会分摊到应用程序中的所有其他操作(相比之下,将像素推送到屏幕的开销真的)。

如果一个对象跨线程共享(通常是个坏主意),那么保护数据访问和操作的锁定开销通常会远远大于保留/释放开销,因为保留/释放的频率不高。


就 Python 的 GIL 开销而言,我敢打赌它更多地与引用计数作为正常解释器操作的一部分递增和递减的频率有关。

关于objective-c - Apple 的 Objective-C 运行时如何在不降低性能的情况下进行多线程引用计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13942226/

相关文章:

php - 将存档的 iOS objective-c 对象发送到 php 并保存到 mysql 数据库并检索

java - 强制线程每天在特定时间执行操作

android - Android 中的多线程

java - 具有许多不同 View 的 ListView 适配器

java while循环下载时如何计算Mbit/s

ios - 如何为缩略图快速加载图像的低分辨率版本?或者简单地说,如何最好地创建缩略图?

iOS计算重力

r - 是否有更快的方法来计算 r 中栅格堆栈的中位数?

iphone - 数据保护开启 : standardUserdefaults corrupted after iOS restart

java - 如何实现一个单独的线程,在主循环运行时评估用户输入?