在没有能够执行垃圾收集的更高功率的本机系统(例如 VM)中,在性能或复杂性方面不会比引用计数更好。
你是对的,引用计数可能很棘手 - 不仅增量和减量必须是原子的,而且你需要确保在你能够增加它之前不能从你下面删除对象。因此,如果将引用计数器存储在对象中,则必须以某种方式避免在从缓存中读取指向对象的指针和设法递增指针之间发生的竞争。
如果您的结构是标准容器,它还不是线程安全的,您还必须保护容器免受不受支持的并发访问。这种保护可以很好地与避免上述引用计数竞争条件相吻合 - 如果您使用读写器锁来保护结构,并结合对象内引用计数器的原子增量同时仍持有读卡器锁,您将在您获得引用计数之前,防止任何人从您身下删除该对象,因为此类变异器必须是“作者”。
在这里,对象可以从缓存中逐出,同时仍然具有正引用计数 - 当最后一个未完成的引用被删除时(通过您的智能指针类),它们将被销毁。这通常被认为是一个特性,因为它意味着至少一些对象总是可以从缓存中删除,但它也有一个缺点,即内存中“活动”对象的数量没有严格的上限,因为引用计数允许对象即使在离开缓存后仍能说活着。您是否可以接受这取决于您的要求和细节,例如其他线程可以持有对对象的引用多长时间。
如果您无权访问(非标准)原子增量例程,则可以使用互斥锁来执行原子增量/减量,尽管这可能会显着增加时间和每个对象空间的成本。
如果您想变得更奇特(更快),您需要设计一个本身是线程安全的容器,并提出更复杂的引用计数机制。例如,您可以创建一个哈希表,其中主存储桶数组永远不会重新分配,因此可以在没有锁定的情况下访问。此外,您可以在该数组上使用不可移植的双宽 CAS(比较和交换)操作来读取指针并增加与其相邻的引用计数(64 位拱门上的 128 位内容),允许您避免上述比赛。
完全不同的方法是实施某种“延迟安全删除”策略。这里完全避免引用计数。您从缓存中删除引用,但不要立即删除对象,因为其他线程可能仍持有指向该对象的指针。然后稍后在某个“安全”时间删除该对象。当然,诀窍在于发现何时存在这样的安全时间。基本策略涉及每个线程在“进入”和“离开”危险区域时发出信号,在此期间它们可以访问缓存并保存对包含对象的引用。一旦从缓存中删除对象时处于危险区域的所有线程都离开了危险区域,您可以释放该对象,同时确保没有更多的引用被持有。
这有多实用取决于您的应用程序中是否具有逻辑“进入”和“离开”点(许多面向请求的应用程序都会),以及“进入”和“离开”成本是否可以在多个缓存中分摊访问。好处是没有引用计数!当然,你仍然需要一个线程安全的容器。
通过查看链接here 的论文,您可以找到有关该主题的许多学术论文的参考以及一些实际性能考虑。