5

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

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

[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. 使操作原子化将是困难/痛苦的。

在我看来,GC 已经不得不处理其中的一些问题。那我忘记了什么?

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

注意2:另外,我不关心编组。我只是担心钉住。

4

1 回答 1

9

GC 只知道无论你接下来要做什么都行不通。你固定内存是有原因的,肯定是为了获得一个稳定的 IntPtr 到对象。然后,您接下来将其传递给非托管代码。

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

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

于 2013-06-19T00:32:16.783 回答