[英]System.OutOfMemory exception when calling MemoryStream.ToArray() after serializing object with DataContractSerializer
在此聲明中,我收到間歇性的“內存不足”異常:
return ms.ToArray();
在這種方法中:
public static byte[] Serialize(Object inst)
{
Type t = inst.GetType();
DataContractSerializer dcs = new DataContractSerializer(t);
MemoryStream ms = new MemoryStream();
dcs.WriteObject(ms, inst);
return ms.ToArray();
}
我該如何預防? 有一個更好的方法嗎?
ms 的長度為 182,870,206 字節 (174.4 MB)
我將它放入一個字節數組中,以便我可以通過壓縮運行它並將其存儲到磁盤。 當我的 silverlight 應用程序啟動時,數據(顯然)是我從 WCF 服務器下載的自定義 class 的大量列表。 我正在對其進行序列化並對其進行壓縮,因此它在隔離存儲中僅使用了大約 6MB。 下次用戶從 web 訪問並運行 silverlight 應用程序時,我檢查時間戳,如果正確,我只需打開隔離文件,解壓縮,反序列化,然后加載我的結構。 我將整個結構保留在 memory 中,因為該應用程序主要是針對操縱該結構的內容。
@configurator 是正確的。 數組的大小太大。 我通過自己的序列化程序滾動,通過聲明 [list record count * byte count per record] 的字節數組,然后使用如下語句直接填充它:
Buffer.BlockCopy(
BitConverter.GetBytes(node.myInt),0,destinationArray,offset,sizeof(int));
offset += sizeof(int);
這是為了取回它:
newNode.myInt= BitConverter.ToInt32(sourceByteArray,offset);
offset += sizeof(int);
然后我將其壓縮並將其存儲到隔離存儲中。
我的大小從使用 DataContractSerializer 的 174MB 變為使用我的 14MB。 壓縮后,它在隔離存儲中從 6MB 變為 1MB 文件。
感謝 Configurator 和 Filip 的幫助。
問題似乎是您期望返回一個 180MB 字節數組。 這意味着框架需要找到並分配連續 180MB 的空閑 memory 以將 stream 數據復制到其中,這通常非常困難 - 因此會出現 OutOfMemoryException。 如果需要繼續處理這個量的memory,使用memory stream本身(根據需要讀寫)來持有緩沖區; 否則,將其直接保存到文件(或您需要的任何其他地方,例如通過網絡提供服務),而不是使用 memory stream。
我應該提一下,memory stream 也有一個 180MB 的數組,所以也有一些麻煩,並且可能在序列化過程中導致 OutOfMemory - 如果你可以序列化它可能會更好(如,更健壯)它到一個臨時文件。 您可能還想考慮一種更緊湊但可能不太可讀的序列化格式,例如 json、二進制序列化或協議緩沖區。
回應評論:要直接序列化到磁盤,請使用FileStream
而不是MemoryStream
:
public static void Serialize(Object inst, string filename)
{
Type t = inst.GetType();
DataContractSerializer dcs = new DataContractSerializer(t);
using (FileStream stream = File.OpenWrite(filename)) {
dcs.WriteObject(ms, inst);
}
}
我不知道您如何使用該代碼,但讓我印象深刻的一件事是您沒有釋放您的資源。 例如,如果您使用大量大對象多次調用Serialize(obj)
,您最終將使用大量未直接釋放的 memory,但是GC
應該正確處理該問題,但您應該始終釋放你的資源。
我試過這段代碼:
public static byte[] Serialize(object obj)
{
Type type = obj.GetType();
DataContractSerializer dcs = new DataContractSerializer(type);
using (var stream = new MemoryStream())
{
dcs.WriteObject(stream, obj);
return stream.ToArray();
}
}
在控制台應用程序中使用以下Main
方法
static void Main(string[] args)
{
var filipEkberg = new Person {Age = 24, Name = @"Filip Ekberg"};
var obj = Serialize(filipEkberg);
}
但是,我的byte
-array 沒有你的那么大。 看看這個類似的問題,您可能需要考慮檢查protobuf-net 。
知道您打算如何處理序列化數據也可能很有趣,您是否需要將其作為byte
數組,或者也可以將 XML 寫入文本文件?
嘗試序列化為 stream(即 FileStream)而不是字節數組。 這樣您就可以序列化千兆字節的數據而不會出現 OutOfMemory 異常。
public static void Serialize<T>(T obj, string path)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
Stream stream = File.OpenWrite(path);
serializer.WriteObject(stream, obj);
}
public static T Deserialize<T>(string path)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
Stream stream = File.OpenRead(path);
return (T)serializer.ReadObject(stream);
}
嘗試將 memory stream position 設置為 0,然后僅調用 ToArray()。
問候。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.