我有一个包含大量用于报告的数据的对象。为了从服务器到客户端获取此对象,我首先在内存流中序列化对象,然后使用.NET的Gzip流压缩它。然后我将压缩对象作为byte []发送到客户端。
问题在于某些客户端,当他们获取byte []并尝试解压缩和反序列化对象时,会抛出System.OutOfMemory异常。我已经读过这个异常可能是由new()引起的一堆对象引起的,或者是一堆字符串引起的。这两种情况都发生在反序列化过程中。
所以我的问题是:如何防止异常(任何好的策略)?客户端需要所有数据,并尽可能地减少了字符串的数量。
编辑:这是我用来序列化/压缩的代码(实现为扩展方法)
public static byte[] SerializeObject<T>(this object obj, T serializer) where T: XmlObjectSerializer
{
Type t = obj.GetType();
if (!Attribute.IsDefined(t, typeof(DataContractAttribute)))
return null;
byte[] initialBytes;
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream, obj);
initialBytes = stream.ToArray();
}
return initialBytes;
}
public static byte[] CompressObject<T>(this object obj, T serializer) where T : XmlObjectSerializer
{
Type t = obj.GetType();
if(!Attribute.IsDefined(t, typeof(DataContractAttribute)))
return null;
byte[] initialBytes = obj.SerializeObject(serializer);
byte[] compressedBytes;
using (MemoryStream stream = new MemoryStream(initialBytes))
{
using (MemoryStream output = new MemoryStream())
{
using (GZipStream zipper = new GZipStream(output, CompressionMode.Compress))
{
Pump(stream, zipper);
}
compressedBytes = output.ToArray();
}
}
return compressedBytes;
}
internal static void Pump(Stream input, Stream output)
{
byte[] bytes = new byte[4096];
int n;
while ((n = input.Read(bytes, 0, bytes.Length)) != 0)
{
output.Write(bytes, 0, n);
}
}
这是我的解压缩/反序列化代码:
public static T DeSerializeObject<T,TU>(this byte[] serializedObject, TU deserializer) where TU: XmlObjectSerializer
{
using (MemoryStream stream = new MemoryStream(serializedObject))
{
return (T)deserializer.ReadObject(stream);
}
}
public static T DecompressObject<T, TU>(this byte[] compressedBytes, TU deserializer) where TU: XmlObjectSerializer
{
byte[] decompressedBytes;
using(MemoryStream stream = new MemoryStream(compressedBytes))
{
using(MemoryStream output = new MemoryStream())
{
using(GZipStream zipper = new GZipStream(stream, CompressionMode.Decompress))
{
ObjectExtensions.Pump(zipper, output);
}
decompressedBytes = output.ToArray();
}
}
return decompressedBytes.DeSerializeObject<T, TU>(deserializer);
}
我传递的对象是一个包装器对象,它只包含保存数据的所有相关对象。对象的数量可以很多(取决于报告的日期范围),但我已经看到多达25k个字符串。
我忘记提到的一件事是我正在使用WCF,并且由于内部对象通过其他WCF调用单独传递,我使用的是DataContract序列化程序,并且所有对象都使用DataContract属性进行标记。
答案 0 :(得分:0)
如果您还没有这样做,可以在客户端尝试pre-generating the XmlSerializer assemblies。
.NET实际上是在运行时生成这些内容,除非您预先生成并链接它们。
更多:Sgen.exe以及StackOverflow上的更多内容。
答案 1 :(得分:0)
我工作的开发人员遇到了类似的问题,其中用于序列化的大型流碎片化了内存堆,垃圾收集器无法将其压缩到足以允许他重新分配内存。
如果要重复序列化多个对象,我会分配一个缓冲区,然后在每次完成时清除它,而不是处理它并创建一个新缓冲区。这样你只需要内存来创建一次,然后你的应用程序应该继续有效地工作。
我还提到@yetapb评论说可能会以流式方式分页和编写数据。这样你就不需要内存中的巨大缓冲区来存储数据。