我能想到的最简单的短期解决方案(我猜我正在寻找一个短期和长期的答案)是在完成序列化处理后立即调用GC.Collect。在我看来,这将从LOH垃圾收集对象,并且在其他对象被添加到它之前可能会这样做。这将使其他对象紧密地贴合堆中剩余的对象,而不会引起太多的碎片化。
除了这个荒谬的90MB分配外,我认为我没有任何其他使用LOH的东西了。这个90 MB分配也相对罕见(大约每4个小时)。当然,我们仍将在其中保留1.5 MB的数组和可能还有一些较小的序列化对象。
有任何想法吗?
更新:由于好的反馈而更新
这里是我的代码,它执行了该工作。实际上,我尝试更改此代码以便在序列化时进行压缩,以便序列化同时将序列化到流中,但结果并不理想。我还尝试将内存流预分配到100 MB,并尝试连续两次使用同一流,但LOH仍会达到180 MB。我使用Process Explorer来监视它。太疯狂了。下一个想法我想尝试使用UnmanagedMemoryStream。如果您愿意,请尝试它。它不必是这个确切的代码。只需序列化大型数据集即可获得出乎意料的结果(我的数据集有很多表,约15张表和许多字符串和列)。
byte[] bytes;
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
serializer.Serialize(memStream, obj);
bytes = CompressionHelper.CompressBytes(memStream.ToArray());
memStream.Dispose();
return bytes;
尝试使用UnmanagedMemoryStream进行二进制序列化后的更新
即使我将对象序列化到UnmanagedMemoryStream中,LOH的大小仍然会增加。似乎无论我做什么,调用BinaryFormatter来序列化这个大对象都会使用LOH。至于预分配,似乎没有什么帮助。比如说,我预分配了100MB,然后我进行序列化,它将使用170MB。以下是代码,比上面的代码更简单。
BinaryFormatter serializer = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(1024*1024*100);
GC.Collect();
serializer.Serialize(memoryStream, assetDS);
中间的GC.Collect()仅用于更新LOH性能计数器。您将看到它将分配正确的100 MB。但是,当您调用序列化时,您会注意到它似乎会在已经分配的100 MB之上添加。