.net - 从托管 'ref' 内部指针中恢复包含 GC 对象
问题描述
鉴于最新版本的C# 7中的新ref locals和ref return功能,这个问题是新的相关:
随着 C# 中托管或“内部”指针变量的日益突出和更广泛的使用,有时您可能需要为此类指针恢复相应的包含 Pinnable
GC 对象。例如,如果您将托管指针传递给类型为 的数组元素T
,则可能需要数组引用T[]
本身才能调用 (eg) Array.Copy(...)
。
因此,从托管代码中,考虑到以下流行的内部/托管指针 ( , , ) 的使用,是否有任何合理合法的方法来恢复包含的 GC 对象句柄:
ref
out
in
- 指向GC 对象实例中(
struct
或class
)字段的内部指针; - 指向Array的(
struct
或class
)元素 的托管指针。T
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,它甚至可能不相关。
我还查看了 newSpan<T>
和System.Memory
库,但是如果您没有首先提供数组句柄,则找不到可以恢复(例如)数组句柄的操作序列(因此包含句柄在那些各种结构)。如果_pinnable
是可选的(例如Span<T>
),则结构中的 GC 句柄是null
,因此如果您不从一开始就选择加入,则无法将其取回。
摘要:有没有办法从托管指针中恢复包含对象的句柄?
[编辑:] 如果托管指针指向堆栈上的值类型,那么(假定的)句柄恢复函数通过(例如)返回“null”来指示失败是完全合理的。
解决方案
不,不可能从内部指针恢复包含对象。在 GC 期间,由于所谓的砖表和插头树,内部指针被转换为相应的对象。给定一个指定的地址,计算正确的砖表条目并遍历相应的插头树以找到该地址所在的插头。最后,逐个对象扫描该插件以找到包含所考虑地址的插件。
关键是这些树仅在 GC 期间构建并可用。因此,即使存在这样的“内部指针恢复”API,它也必须等待 GC,并且只能在之后提供答案(这似乎非常不切实际)。其他解决方案,如线性内存扫描,显然可能会引入巨大的开销。
推荐阅读
- javascript - 使用 javascript 中的正则表达式在文本框中输入文本时格式化许可证号
- c# - 使用绑定参数更新模型会使那些不在形式中的模型无效
- java - 当我将方向更改为纵向时,AndroidTV VideoView 播放声音但没有视频
- python - 如何在元组列表中找到特定数据类型的最大值并用这些值更新字典?
- python-3.x - 收到“只能连接 str(不是浮动)”的错误
- typescript - 从 API 或 gcloud 在 firebase 项目中启用登录方法
- flutter - 未定义的类“TabController”。我怎样才能恢复这个小部件?
- list - 将列表拆分为奇数和偶数(Haskell)
- visual-studio-code - VSCode Python Intellisense 不适用于 .env 文件中的自定义 PYTHONPATH
- html - 水平拆分,拆分下方和上方的文本