我怀疑这个功能不存在的原因是实现起来很复杂,而且很少有人需要它。为了安全起见,您希望固定能够传递地工作,即您希望固定可到达对象的整个图。但这似乎并不是根本做不到的事情。
例如,假设您有以下课程:
[StructLayout(LayoutKind.Sequential)]
class SomeObject
{
public SomeObject r;
}
您分配的方式如下:
SomeObject o = new SomeObject();
然后你尝试用以下方式固定它:
GCHandle oh = GCHandle.Alloc(o, GCHandleType.Pinned);
你会遇到可怕的:
Object contains non-primitive or non-blittable data.
好吧,好吧,我可以接受。但假设我可以访问 .NET 的垃圾收集器实现。会有什么障碍?以下是我看到的障碍:
在我看来,GC 已经必须处理其中一些问题了。那么我忘记了什么?
注意:在你问“你想完成什么?”等问题之前,我问的目的是为了研究代码,不一定限于C#,也不一定限于CLR。我知道摆弄运行时自己的内存并不是典型的场景。无论如何,这不是一个纯粹的推测性问题。
注 2:另外,我不关心编组。我只是担心固定。
GC 只知道无论你接下来要做什么都是行不通的。你固定内存是有一个原因,肯定是为了给对象获取一个稳定的IntPtr。然后,您接下来将其传递给非托管代码。
然而,指向内存的内容存在问题。它包含一个指向托管对象的指针。每当另一个线程分配内存并触发集合时,该指针就会“随机”更改。这将对任何使用固定内存内容的代码造成严重破坏。没有办法获得稳定的指针,你无法“冻结”收集器。固定指针也不起作用,它只是将责任传递给下一个指向的对象。 GCHandle.Alloc 不会遍历整个依赖关系图来检查这一点,对于需要多长时间没有合适的上限。循环引用在托管代码中完全合法,但检测起来非常昂贵。固定整整一代人在技术上是可能的,这是一个非常艰难的僵局。 丑陋的问题,禁止它要简单得多。没什么大问题,反正 pinvoke 每天都会发生。