从托管 'ref' 内部指针中恢复包含 GC 对象
Recover containing GC object from managed 'ref' interior pointer
鉴于最新版本的 ref locals 和 ref 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:
- GC对象实例中指向(
struct
或class
)字段的内部指针;
- 指向数组
T[]
.[=68= 的(struct
或 class
) 元素 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 table 和 plug trees,内部指针被翻译成相应的对象。给定一个指定的地址,计算出正确的 brick table 条目并遍历相应的 plug 树以找到该地址所在的 plug。最后,逐个对象扫描该插头以找到包含所考虑地址的插头。
关键是那些树是构建的并且仅在 GC 期间可用。所以,即使存在这样的 "interior pointer recovery" API ,它也必须等待 GC,然后才能提供答案(这似乎很不切实际)。其他解决方案,如线性内存扫描,显然可能会带来巨大的开销。
鉴于最新版本的 ref locals 和 ref 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:
- GC对象实例中指向(
struct
或class
)字段的内部指针; - 指向数组
T[]
.[=68= 的(struct
或class
) 元素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 table 和 plug trees,内部指针被翻译成相应的对象。给定一个指定的地址,计算出正确的 brick table 条目并遍历相应的 plug 树以找到该地址所在的 plug。最后,逐个对象扫描该插头以找到包含所考虑地址的插头。
关键是那些树是构建的并且仅在 GC 期间可用。所以,即使存在这样的 "interior pointer recovery" API ,它也必须等待 GC,然后才能提供答案(这似乎很不切实际)。其他解决方案,如线性内存扫描,显然可能会带来巨大的开销。