Serialisierung von Chunked-Byte-Arrays mit Protobuf-net

In unserer Anwendung haben wir einige Datenstrukturen, die unter anderem eine unterteilte Liste von Bytes enthalten (derzeit verfügbar als aList<byte[]>). Wir teilen Bytes auf, weil mit der Zeit Speicherfragmentierung auftritt, wenn wir zulassen, dass die Bytearrays auf dem großen Objekthaufen abgelegt werden.

Wir haben auch damit begonnen, Protobuf-net zu verwenden, um diese Strukturen mit unserer selbst erstellten Serialisierungs-DLL zu serialisieren.

Wir haben jedoch festgestellt, dass Protobuf-net beim Serialisieren sehr große In-Memory-Puffer erstellt. Ein Blick in den Quellcode zeigt, dass der interne Puffer möglicherweise nicht vollständig geleert werden kannList<byte[]> Die Struktur wurde geschrieben, weil sie danach die Gesamtlänge an der Vorderseite des Puffers schreiben muss.

Dies macht unsere Arbeit mit dem Chunking der Bytes unglücklicherweise rückgängig und führt schließlich zu OutOfMemoryExceptions aufgrund von Speicherfragmentierung (die Ausnahme tritt zu dem Zeitpunkt auf, zu dem Protobuf-net versucht, den Puffer auf über 84 KB zu erweitern, was es offensichtlich auf den Speicher legt LOH, und unser gesamter Prozessspeicherbedarf ist ziemlich niedrig.

Wenn meine Analyse der Funktionsweise von Protobuf-net korrekt ist, gibt es einen Weg, um dieses Problem zu umgehen?

Aktualisieren

Basierend auf Marc's Antwort habe ich Folgendes versucht:

[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;
    }
}

Dann, um es zu serialisieren:

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);

Allerdings, wenn ich einen Haltepunkt in steckeProtoWriter.WriteBytes() wo es anruftDemandSpace() zum Ende der Methode und Schritt inDemandSpace()Ich kann sehen, dass der Puffer nicht geleert wird, weilwriter.flushLock gleich1.

Wenn ich eine andere Basisklasse für ABase wie folgt erstelle:

[ProtoContract]
[ProtoInclude(1, typeof(ABase), DataFormat = DataFormat.Group)]
public class ABaseBase
{
}

[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase : ABaseBase
{
}

Dannwriter.flushLock gleich2 imDemandSpace().

Ich vermute, es gibt einen offensichtlichen Schritt, den ich hier versäumt habe, um mit abgeleiteten Typen zu tun?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage