4

データをFIFOに設定し、別のスレッドがFIFO内のこのデータを1つずつ読み取り、後でネットワーク経由で送信するタスクがあります。FIFO.Add次のように、 を呼び出すときにデータがバイト配列に変換されます。

public byte[] ByteArraySerialize()
{
    using (MemoryStream m = new MemoryStream())
    {
        using (BinaryWriter writer = new BinaryWriter(m))
        {
            writer.Write((int)this.Opcode);
            writer.Write(this.Data);
        }
        return m.ToArray();
    }
}

私の質問: 送信スレッドが FIFO からデータを読み取る前に、データが破損または破棄される可能性はありますか? 私の質問は、usingメソッド内を理解することです: これは、スレッドがデータを読み取る前に、このデータが FIFO に入ってから数秒または数分後に言う前にusing、メソッド内で GC が を削除する原因になる可能性がありますか?MemoryStream

4

4 に答える 4

6

この質問を読むには複数の方法がありますが、明白な方法、それが書かれた方法から始めましょう。

メソッド内で「使用」を使用すると、スレッドがデータを読み取る前に、このデータが FIFO に入ってから数秒または数分後に GC がメモリ ストリームを削除する可能性がありますか?

いいえ、問題ありません。への呼び出しの一部としてデータを読み取ることができる場合は.ToArray()、データのコピーが既にあります。後で GC がストリームを収集した場合、アレイは存続します。明確にするために、GC に関して、呼び出した時点でストリームの内部の適切なコピーを読み取ることができれば、.ToArray()その配列は後で問題ありません。ドキュメントによると、内部データへの参照ではなく、内部データのコピーを取得しています。それでも、内部データ構造への参照がある場合、GC はそれを収集できません。

ただし、別の解釈は次のようになります。このコードには何か問題がありますか?

はい、いいえ。

の現在の実装でBinaryWriterは、ライター インスタンスが破棄されると、基になるストリームが破棄されます。これは、MemoryStream処分されることを意味します。

コードをコピーしてコメントを追加さ​​せてください。

public byte[] ByteArraySerialize()
{
    using (MemoryStream m = new MemoryStream())
    {
        using (BinaryWriter writer = new BinaryWriter(m))
        {
            writer.Write((int)this.Opcode);
            writer.Write(this.Data);
        }

        // m is really disposed here
        return m.ToArray();
    }
}

これは違いがありますか?うーん、ダメ。現在の実装では、メモリ ストリームを破棄しても決して破棄されません。ただし、現在の実装またはその将来について保証されるものは何もありません。これは文書化されていない動作です。このコードを将来のバージョンや .NET の修正プログラムで安定して信頼できるものにしたい場合は、このようには書きません。

そのため、私はこの方法を使用しません。次のようにコードを書き直します。

using (MemoryStream m = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(m))
{
    writer.Write((int)this.Opcode);
    writer.Write(this.Data);

    writer.Flush();
    return m.ToArray();
}

これはライターにすべてのデータをフラッシュするように要求し、そのインスタンスが破棄される前に、メモリ ストリームの内部配列のコピーを作成します。

それか、オーバーロードされたコンストラクターを使用して、ライターにストリームを開いたままにするように依頼します。

using (MemoryStream m = new MemoryStream())
{
    using (BinaryWriter writer = new BinaryWriter(m, Encoding.UTF8, true))
    {
        writer.Write((int)this.Opcode);
        writer.Write(this.Data);
    }

    // m is no longer disposed here
    return m.ToArray();
}
于 2013-11-02T19:40:17.180 に答える
5

を呼び出すとToArray();、必要なデータのコピーが効果的に作成されます。
したがって、MemStreams に発生するすべてのことは無関係です。

より一般的には、コードがデータの一部を「見る」ことができる限り、GC はその一部をリサイクルできません。
これを考えすぎないでください。

以下を使用したとします。

 return m.GetBuffer();

これで、MemStream の内部バッファーが返されます。mDisposed になりますが、単にそれを返したという理由だけで、バッファはその所有者よりも長生きします。

于 2013-11-02T19:33:17.470 に答える
1

あなたの質問に対する答えは、「この場合ではありません」だと思います。もちろん、メモリ ストリームを破棄することもできますが、その前に、データを byte[] 配列に保持します。

writer.Flush();の直後に追加してみてくださいwriter.Write(this.Data);

于 2013-11-02T19:35:47.330 に答える
0

いいえ、問題ありません。ストリームの破棄が早すぎることはありません。

あなたはGCについて話しますが、usingステートメントとのアイデアIDisposableは、オブジェクトが範囲外になるとすぐにリソースが解放されるということです。GC を待つ必要はありません。つまり、これは GC とは関係ありません。

于 2013-11-02T19:31:33.737 に答える