为什么GCHandle.Alloc不能包含引用的pin对象?

时间:2013-06-19 00:07:18

标签: c# garbage-collection pinvoke

我怀疑这个功能不存在的原因是实现它很复杂,很少有人需要它。为了安全起见,您需要固定工作,即,您希望固定可到达对象的整个图形。但它似乎并不是从根本上无法完成的事情。

例如,假设您有以下课程:

[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的垃圾收集器实现。会有什么障碍?以下是我看到的障碍:

  1. 循环引用。
  2. 您希望垃圾收集器将自己限制在应用程序堆内的对象。
  3. 可能需要很长时间。
  4. 使操作原子化会很困难/痛苦。
  5. 在我看来,GC已经必须处理其中的一些问题。那我忘记了什么?

    注意:在你问“你想要完成什么?”等之前,我要求的目的是研究代码,不一定限于C#,也不一定限于CLR。我知道摆弄运行时自己的内存并不是一个典型的场景。无论如何,这不是一个纯粹的推测性问题。

    注2:另外,我不关心编组。我只关心钉扎。

1 个答案:

答案 0 :(得分:9)

GC只知道你接下来的任何事情都不会起作用。你为原因固定内存,肯定是为了获得对象的稳定IntPtr。然后,接下来,您将传递给非托管代码。

指向内存的内容存在问题。它包含指向托管对象的指针。每当另一个线程分配内存并触发集合时,该指针将随机更改。这将对使用固定内存内容的任何代码造成严重破坏。没有办法获得稳定的指针,你不能“冻结”收藏家。固定指针也不起作用,它只是将降压传递给下一个指向的对象。希望它迟早会变为空,它必须,但是GC.Alloc不会遍历整个依赖图来检查,可能需要多长时间没有正常的上限。让整整一代人固定是可能的,这是一个非常困难的僵局。

丑陋的问题,禁止它只是简单得多。不是真正的问题,无论如何都会发生pinvoke。