Uso da memória serializando matrizes de byte em partes com Protobuf-net

Em nosso aplicativo, temos algumas estruturas de dados que, entre outras coisas, contêm uma lista de bytes em partes (atualmente exposta comoList<byte[]>). Nós dividimos bytes porque, se permitirmos que as matrizes de bytes sejam colocadas no heap de objetos grandes, com o tempo, sofreremos fragmentação de memória.

Também começamos a usar o Protobuf-net para serializar essas estruturas, usando nossa própria DLL de serialização gerada.

No entanto, notamos que o Protobuf-net está criando buffers de memória muito grandes durante a serialização. Olhando através do código fonte, parece que talvez ele não consiga liberar seu buffer interno até queList<byte[]> estrutura foi escrita porque precisa escrever o comprimento total na frente do buffer depois.

Isto infelizmente desfaz o nosso trabalho com chunking os bytes em primeiro lugar, e eventualmente nos dá OutOfMemoryExceptions devido a fragmentação de memória (a exceção ocorre no momento em que Protobuf-net está tentando expandir o buffer para mais de 84k, o que obviamente o coloca no LOH e nosso uso geral da memória do processo é razoavelmente baixo).

Se minha análise de como o Protobuf-net está funcionando está correta, há uma maneira de contornar esse problema?

Atualizar

Com base na resposta de Marc, aqui está o que eu tentei:

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

Então para serializá-lo:

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

No entanto, se eu colocar um ponto de interrupçãoProtoWriter.WriteBytes() onde chamaDemandSpace() em direção ao fundo do método e entrar emDemandSpace(), Eu posso ver que o buffer não está sendo liberado porquewriter.flushLock é igual a1.

Se eu criar outra classe base para o ABase assim:

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

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

Entãowriter.flushLock é igual a2 emDemandSpace().

Eu estou supondo que há um passo óbvio que eu perdi aqui para fazer com tipos derivados?

questionAnswers(2)

yourAnswerToTheQuestion