私たちのアプリケーションには、特にバイトのチャンクリストを含むいくつかのデータ構造があります(現在は として公開されていますList<byte[]>
)。バイト配列を大きなオブジェクト ヒープに配置できるようにすると、時間の経過とともにメモリの断片化が発生するため、バイトをチャンクアップします。
また、独自に生成したシリアライゼーション DLL を使用して、Protobuf-net を使用してこれらの構造をシリアライズすることも開始しました。
ただし、シリアル化中に Protobuf-net が非常に大きなメモリ内バッファーを作成していることに気付きました。ソースコードをざっと見てみると、List<byte[]>
後でバッファの先頭に全長を書き込む必要があるため、構造全体が書き込まれるまで内部バッファをフラッシュできないようです。
残念なことに、これは最初にバイトをチャンク化する作業を元に戻し、最終的にはメモリの断片化のために OutOfMemoryExceptions を発生させます (例外は、Protobuf-net がバッファーを 84k を超えて拡張しようとしているときに発生します。 LOH であり、全体的なプロセス メモリの使用量はかなり低いです)。
Protobuf-net の動作に関する私の分析が正しい場合、この問題を回避する方法はありますか?
アップデート
マークの答えに基づいて、私が試したことは次のとおりです。
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase
{
}
[ProtoContract]
public class A : ABase
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public B B
{
get;
set;
}
}
[ProtoContract]
public class B
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public List<byte[]> Data
{
get;
set;
}
}
次に、それをシリアル化します。
var a = new A();
var b = new B();
a.B = b;
b.Data = new List<byte[]>
{
Enumerable.Range(0, 1999).Select(v => (byte)v).ToArray(),
Enumerable.Range(2000, 3999).Select(v => (byte)v).ToArray(),
};
var stream = new MemoryStream();
Serializer.Serialize(stream, a);
ただし、メソッドの下部に向かっProtoWriter.WriteBytes()
て呼び出す場所にブレークポイントを設定してにステップインすると、 equals が原因でバッファーがフラッシュされていないことがわかります。DemandSpace()
DemandSpace()
writer.flushLock
1
次のように ABase の別の基本クラスを作成すると:
[ProtoContract]
[ProtoInclude(1, typeof(ABase), DataFormat = DataFormat.Group)]
public class ABaseBase
{
}
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase : ABaseBase
{
}
次ににwriter.flushLock
等しい。2
DemandSpace()
派生型を扱うために、ここで見逃した明らかなステップがあると思いますか?