从托管 'ref' 内部指针中恢复包含 GC 对象

Recover containing GC object from managed 'ref' interior pointer

鉴于最新版本的 ref localsref return 新特性,这个问题是新相关的C# 7:

随着 C# 中托管或“内部”指针变量的日益突出和广泛使用,有时您可能需要恢复相应的 containing Pinnable 这样一个指针的GC对象。例如,如果您将托管指针传递给类型为 T 的数组元素,您可能需要数组引用 T[] 本身才能调用(例如)Array.Copy(...).

So, from managed code, is there any reasonably legitimate way to recover the containing GC object handle, given either of the following prevalent interior/managed pointer (ref, out, in) uses:

  1. GC对象实例中指向(structclass字段的内部指针;
  2. 指向数组 T[].[=68= 的(structclass 元素 T 的托管指针]

.NET内部,GC似乎使用了以下函数:/coreclr/master/src/gc/gc.cpp

#ifdef INTERIOR_POINTERS
// will find all heap objects (large and small)
uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low)
{
    ....

此代码遍历已知的 GC 堆,检查指定的内部指针是否在已知的 GC 对象分配范围内。显然,这种方法不容易从最终用户管理的代码访问,而且据我所知,如果没有正在进行的 GC,它甚至可能不相关。

我还查看了新的 Span<T>System.Memory 库,但找不到可以恢复(例如)数组句柄的操作序列,如果您不首先提供它首先出现(因此包含句柄在那些不同的结构中被隐藏起来)。在 _pinnable 是可选的情况下(例如 Span<T>),结构中的 GC 句柄是 null,所以如果你不从一开始就选择加入,就没有办法拿回来。

总结:有没有办法从托管指针恢复包含对象句柄?

[编辑:]如果托管指针指向堆栈上的值类型,那么(假定的)句柄恢复函数通过(例如)returning [来指示失败是完全合理的=75=].


相关:

不,不可能从内部指针恢复包含对象。在 GC 期间,由于所谓的 brick tableplug trees,内部指针被翻译成相应的对象。给定一个指定的地址,计算出正确的 brick table 条目并遍历相应的 plug 树以找到该地址所在的 plug。最后,逐个对象扫描该插头以找到包含所考虑地址的插头。

关键是那些树是构建的并且仅在 GC 期间可用。所以,即使存在这样的 "interior pointer recovery" API ,它也必须等待 GC,然后才能提供答案(这似乎很不切实际)。其他解决方案,如线性内存扫描,显然可能会带来巨大的开销。