簡體   English   中英

使用 DataContractSerializer 序列化 object 后調用 MemoryStream.ToArray() 時出現 System.OutOfMemory 異常

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM