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 を取得するためです。次に、アンマネージ コードに渡すとします。

ただし、ポイント先のメモリの内容に問題があります。これには、管理対象オブジェクトへのポインターが含まれています。そのポインターは、別のスレッドがメモリを割り当ててコレクションをトリガーするたびにランダムに変化します。これは、固定されたメモリ コンテンツを使用するすべてのコードに大混乱をもたらします。安定したポインターを取得する方法はありません。コレクターを「フリーズ」することはできません。ポインタのピン留めも機能しません。次のポイント先のオブジェクトにバックを渡すだけです。遅かれ早かれ null になることを願っていますが、そうする必要がありますが、GC.Alloc はそれを確認するために依存関係グラフ全体を移動するわけではありません。世代全体を固定することは可能です。これは非常にハードなデッドロックです。

醜い問題、それを禁止する方がはるかに簡単でした。ピンボークはとにかく毎日発生します。

于 2013-06-19T00:32:16.783 に答える