【问题标题】:Multithreading, Tracing Garbage Collectors and Native C APIs多线程、跟踪垃圾收集器和原生 C API
【发布时间】:2021-07-30 02:46:16
【问题描述】:

许多带有跟踪垃圾收集器的编程语言原生 C API 都有一个 root 和 unroot 函数来保护临时值不被收集。

在多线程环境中,如果本机函数取消其所有对象的根,然后返回其中一个对象,如果在取消根和返回之间,另一个线程分配导致集合,会发生什么情况?我尝试返回的值是否也会被收集?

我查看了 Ruby、Julia、Janet 和 V8 的解决方案,但我找不到任何明显的解决方案。在多线程环境中只使用一对 root 和 unroot 函数是否安全?

我正在尝试为我的脚本语言构建一个简单的停止世界标记并清除垃圾收集器, 我正在努力使所有需要线程安全的东西变得安全。目前我的垃圾收集器有两个单链表,一个用于分配的对象,另一个用于根,受全局互斥锁保护。

【问题讨论】:

  • 你为什么要取消一个显然仍在使用的值(因为你要返回它)?答案应该是显而易见的。永远不要取消根目录来再次根目录,即使是单个 CPU 周期。

标签: multithreading garbage-collection


【解决方案1】:

如果所有对象都从根对象集中移除,那么所有对象都可以被垃圾回收(可能来自另一个线程)。这包括返回的对象。即使在很短的一段时间内也是如此,除非确保垃圾收集器不会在那段时间内经过(这在并行上下文中很难确保)。

跟踪垃圾收集器有许多不同的实现。 AFAIK,许多将返回的对象存储在垃圾收集器跟踪的堆栈(可能是系统堆栈或手动堆栈)中。该堆栈通常保存(一部分)根对象集。堆栈可以自动管理或手动管理。有被调用者/调用者约定,因此返回的对象永远不会不安全地被“无根”和收集。全局对象引用也可能存在另一种数据结构。例如,R 的 GC 就是这种情况,它非常简单(参见here)。 Java 使用基于线程本地堆栈帧(具有自动存储持续时间)的类似概念用于本地引用。全局引用是隐式创建的,但在低级代码(例如 JNI)中显式手动删除。您可以找到更多信息here

【讨论】:

  • 我读过 R 的,他们仍然没有告诉你对象是如何在多线程程序返回时传播的。至于 API,它与我所说的非常相似,一个 PROTECT 和 UNPROTECT 函数/宏。我考虑过使用线程本地存储来存储每个函数的返回值,但它们与 DLL 不兼容,我也考虑过将线程 ID 映射到值,但我希望更简单的东西不需要分配或重新分配
猜你喜欢
  • 1970-01-01
  • 2011-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 2021-11-19
  • 1970-01-01
相关资源
最近更新 更多