質問

C#では、このようなポインタータイプメンバーを持つ構造体(またはクラス)を宣言することができます。

unsafe struct Node
{
  public Node* NextNode;
}

それはこれまで安全ですか(エラー..皮肉なことをしばらく無視してください unsafe フラグ..)この構造を使用するには?ヒープの長期保管を意味します。私が理解していることから、GCは物事を自由に動かしており、移動されたものへの参照を更新しながら、ポインターも更新しますか?私はノーだと思います、それはこの構造を非常に安全ではないでしょう?

これを行うことには優れた代替手段があると確信していますが、病的な好奇心と呼んでいます。

編集:混乱があるようです。私はこれが素晴らしい構造ではないことを知っています、私は 純粋に これが安全な構造であるかどうかを知りたいのですが、つまり、ポインターはあなたが最初に指摘したものを指し続けることが保証されていますか?

元のCコードは、ツリーが配列に保存されている再帰なしにツリー(最初の深さ)を通過するために使用されました。次に、特定の条件が満たされない限り、ポインターを増加させることにより配列が通過します。ポインターは、トラバーサルが続くNextNodeに設定されます。もちろん、c#でも同じことが、次のことを達成できます。

struct Node
{
  public int NextNode;
  ... // other fields
}

どこ int 次のノードの配列のインデックスです。しかし、パフォーマンス上の理由で、私はポインターをいじることになり、 fixed とにかく境界チェックを回避するための配列であり、元のCコードはより自然に見えました。

役に立ちましたか?

解決

この構造を使用しても安全ですか?私はヒープの長期保管を意味します。

はい。そうすることは通常、愚かで、痛みを伴い、不必要ですが、それは可能です。

私が理解していることから、GCは物事を自由に動かしており、移動されたものへの参照を更新しながら、ポインターも更新しますか?

いいえ。 だから私たちはあなたにそれを安全ではないとマークさせます。

私はノーだと思います、それはこの構造を非常に安全ではないでしょう?

正しい。

これを行うことには優れた代替手段があると確信していますが、病的な好奇心と呼んでいます。

確かにあります。

ポインターは、あなたが元々指し示していたものを指摘し続けることが保証されていますか?

あなたがそれが起こることを保証しない限りではありません。それを行うには2つの方法があります。

1つの方法:ゴミコレクターにメモリを動かないように伝えます。それを行うには2つの方法があります。

  • 「固定」ステートメントを使用して変数を適切に修正します。

  • Interop Servicesを使用して、生かし続けたい構造にGCハンドルを作成します。

これらのどちらかを行うと、高い可能性があると、ガベージコレクターのパフォーマンスが破壊されます。

方法2:ゴミコレクターが移動できるというメモリへの参照を取得しないでください。それを行うには2つの方法があります。

  • ローカル変数、値パラメーター、またはスタックに割り当てられたブロックのアドレスのみを取得します。もちろん、そうすることで、ポインターが関連するスタックフレームよりも長く生き残らないようにする必要があります。そうしないと、ごみを参照しています。

  • 未成年のヒープからブロックを割り当ててから、そのブロック内のポインターを使用します。 Essenseでは、独自のメモリマネージャーを実装してください。新しいカスタムメモリマネージャーを正しく実装する必要があります。気をつけて。

他のヒント

なぜだめですか:

struct Node
{
    public Node NextNode;
}

または少なくとも:

struct Node
{
    public IntPtr NextNode;
}

使用できます 修繕 GCがポインターを移動するのを防ぐための声明。

はい、ゴミコレクターはオブジェクトを動かして、ポインターを更新しません。指すオブジェクトを修正する必要があります。これについては、詳細をご覧ください メモリ管理の説明.

このようなオブジェクトを修正できます。

  unsafe {
     fixed (byte* pPtr = object) {
         // This will fix object in the memory
        }
     }
  }

ポインターの利点は、通常、他の安全でないコードとのパフォーマンスと相互作用です。コードをスピードアップするために、バウンド外のチェックなどがありません。しかし、たとえばCでプログラミングしているかのように、あなたは自分がしていることに非常に注意する必要があります。

いくつかの明らかな整合性チェックは除外されています。これに関する明らかな問題は、バッファをキーワードとして再割り当てすることができないため、必要以上に割り当てる必要があることです 修繕 示す。

public unsafe class NodeList
{
    fixed Node _Nodes[1024];
    Node* _Current;

    public NodeList(params String[] data)
    {
        for (int i = 0; i < data.Length; i++)
        {
            _Nodes[i].Data = data[i];
            _Nodes[i].Next = (i < data.Length ? &_Nodes[i + 1] : null);     
        }

        _Current = &_Nodes[0];
    }

    public Node* Current()
    {
        return _Current++;  
    }
}

public unsafe struct Node
{
    public String Data;
    public Node* Next;
}

危険なアイデアですが、それはうまくいくかもしれません:

構造体の配列が特定のサイズ(85000バイト)を超えると、 大きなオブジェクトヒープ ブロックがスキャンされて収集されますが、移動していない場所...

リンクされた記事は、新しいCLRバージョンがLOHに物を動かす危険性を指摘しています...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top