2015-12-23 65 views
7

我有一個C#.NET系統,它使用JSON數據饋送並使用Newtonsoft.Json.JsonConvert.DeserializeObject轉換器將其轉換爲對象。讀取字符串時發生OutOfMemoryException

這個過程中完美的作品,只要JSON字符串是具有一定規模(幾MB)以下,但只要返回的數據是大(幾乎100兆),我得到的錯誤OutOfMemoryException

此代碼的偉大工程小數據:

// WebClient ------------------------------------------------------------------ 
var _client = new System.Net.WebClient(); 
var _content = _client.DownloadString(_url); 

,但在最後一行炸燬(DownloadString

我試圖改變這個也適用於小型的數據,但它仍然炸燬的ReadToEnd線的時候,數據量增長。

using (var _response = (System.Net.HttpWebResponse)_request.GetResponse()) 
{ 
    using (System.IO.Stream _dataStream = _response.GetResponseStream()) 
    { 
     using (System.IO.StreamReader _streamReader = new System.IO.StreamReader(_dataStream)) 
     { 
      string _responseFromServer = _streamReader.ReadToEnd(); 
     } 
    } 
} 

最後我想這其中的工作:

StringBuilder _stringBuilder = new StringBuilder(); 
using (var _response = (System.Net.HttpWebResponse)_request.GetResponse()) 
{ 
    using (System.IO.Stream _dataStream = _response.GetResponseStream()) 
    { 
     using (System.IO.StreamReader _streamReader = new System.IO.StreamReader(_dataStream)) 
     { 
      while (!streamReader.EndOfStream) 
      { 
       char[] _buffer = new char[4096]; 
       _streamReader.ReadBlock(_buffer, 0, _buffer.Length); 
       var _bufferString = new String(_buffer); 
       _stringBuilder.Append(_bufferString); 
      } 
     } 
    } 
} 

但它與OutOfMemoryException錯誤炸燬了,當它到了下一行的位置:

var _results = Newtonsoft.Json.JsonConvert.DeserializeObject<List<MyObject>>(_stringBuilder.ToString()); 

它不喜歡方法ToString()

它也應聲與像

string _convertedString = _stringBuilder.ToString(); 

完整的錯誤一個簡單的路線是:

類型的異常「System.OutOfMemoryException的」發生在 mscorlib.dll中,但沒有處理用戶代碼

該機器運行帶有16Gb內存的64位窗口。

那麼,我有什麼選擇?

我想要的是一個IQueryable<MyObject>從(非常大)JSON字符串。

+1

檢查出這個問題的答案,http://stackoverflow.com/questions/27315521/system-outofmemoryexception-with-json-net-with-listobject,一次反序列化一個對象 – dbugger

+2

OutOfMemoryException可能由於各種原因而發生,例如耗盡緩衝區,GDI對象等。異常的調用堆棧會告訴您發生了什麼,但真正的罪魁禍首是無效的代碼。 *爲什麼*你可以通過StreamReader讀取數據時使用StringBuilder嗎?你所做的並不比'streamReader更好(或更高效)。ReadToEnd的()'。 –

+0

@PanagiotisKanavos - 這些只是我試圖讓這個工作只是爲了顯示過程的各種方法。如果有一種方法可以將StreamReader中的值存入Deserializer而沒有內存錯誤,那麼我很想知道。 – DeclanMcD

回答

7

您的代碼基本上模擬了StreamReader.ReadToEnd所做的工作,它至少需要讀取大量響應所需內存的4倍(字符串響應本身的內存,StringBuilder的內部緩衝區,所有中間臨時字符串的大小以及最終的串)。

您可以通過直接使用JsonTextReader從流中反序列化來避免這種情況。從documentation sample複製:

using (var json= new JsonTextReader(streamReader)) 
{ 
    JsonSerializer serializer = new JsonSerializer(); 
    return (List<MyObject>)serializer.Deserialize(json, typeof(List<MyObject>)); 
} 

Ø

+0

完美!第一次工作 - 只是對你的代碼進行小小的修改 - 將word文件改爲jsonTextReader – DeclanMcD