【问题标题】:OutOfMemoryException in ProtoBuf-Net SerializationProtoBuf-Net 序列化中的 OutOfMemoryException
【发布时间】:2015-06-15 11:38:06
【问题描述】:

我通过protobuf-net将一些大的Dictionary序列化到磁盘,磁盘上的文件大小为450MB。

通常,代码因 OutOfMemoryException 而失败

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at ProtoBuf.BufferPool.ResizeAndFlushLeft(Byte[]& buffer, Int32 toFitAtLeastBytes, Int32 copyFromIndex, Int32 copyBytes) in c:\Dev\protobuf-net\protobuf-net\BufferPool.cs:line 60
   at ProtoBuf.ProtoWriter.StartSubItem(Object instance, ProtoWriter writer, Boolean allowFixed) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:line 341
   at ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:line 44
   at proto_15(Object , ProtoWriter )
   at ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer, PrefixStyle style, Int32 fieldNumber) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:line 116
   at ProtoBuf.Meta.TypeModel.SerializeWithLengthPrefix(Stream dest, Object value, Type type, PrefixStyle style, Int32 fieldNumber, SerializationContext context) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 548
   at ProtoBuf.Meta.TypeModel.SerializeWithLengthPrefix(Stream dest, Object value, Type type, PrefixStyle style, Int32 fieldNumber) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:line 515
   at ProtoBuf.Serializer.SerializeWithLengthPrefix[T](Stream destination, T instance, PrefixStyle style, Int32 fieldNumber) in c:\Dev\protobuf-net\protobuf-net\Serializer.cs:line 352

机器有 20GB+ 可用内存。

而我的进程只占用 4.6GB

app.config 针对大内存进行了调整

<runtime>
    <gcAllowVeryLargeObjects enabled="true" />
    <gcServer enabled="true"/>
</runtime>

目前我使用try-catch 来捕获异常并在几秒钟后重试。而且它们通常有效。

有没有办法避免这个异常?

【问题讨论】:

    标签: protobuf-net


    【解决方案1】:

    gcAllowVeryLargeObjects 对字节缓冲区没有多大帮助,因为元素数量限制仍然适用 - 但是,奇怪的是它在 450MB 时突破;不要误会我的意思 - 这是相当大的。你是序列化到文件吗?网络?还是只是在内存中?如果它不是纯内存中的,可能有办法说服它需要更少的内部缓冲——例如,切换到组而不是子消息(这只需要一些属性更改)。例如:这个

    public class Foo {
         [ProtoMember(1)]
         public List<Bar> Bars {get; set;}
    }
    

    需要在内存中缓冲Bar数据,其中:

    public class Foo {
         [ProtoMember(1, DataFormat = DataFormat.Group)]
         public List<Bar> Bars {get; set;}
    }
    

    不会。

    【讨论】:

      【解决方案2】:

      我们在尝试通过 WCF 将 300 万条记录从服务端传递到 WPF 客户端的应用程序中遇到了同样的问题。

      解决方案是重建服务端,将序列化为 64 位应用程序(不是 AnyCPU,而是 x64),并确保 APPool 以 64 位模式运行(“允许 32 位应用程序”设置为 False)。

      享受吧!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多