读取字符串时出现OutOfMemoryException

Dec*_*McD 8 c# rest json json.net asp.net-web-api

我有一个C#.NET系统,它使用JSON数据源并使用Newtonsoft.Json.JsonConvert.DeserializeObject转换器将其转换为对象.

只要JSON字符串低于特定大小(几Mb),此过程就可以完美,但只要返回的数据很大(几乎100Mb),我就会收到错误 OutOfMemoryException

此代码适用于小数据:

// WebClient ------------------------------------------------------------------
var _client = new System.Net.WebClient();
var _content = _client.DownloadString(_url);
Run Code Online (Sandbox Code Playgroud)

但在最后一行爆炸(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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后我尝试了这个工作:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是OutOfMemoryException当它到达下一行时会出现错误:

var _results = Newtonsoft.Json.JsonConvert.DeserializeObject<List<MyObject>>(_stringBuilder.ToString());
Run Code Online (Sandbox Code Playgroud)

它不喜欢这种ToString()方法.

它也像一条简单的线坠毁了

string _convertedString = _stringBuilder.ToString();
Run Code Online (Sandbox Code Playgroud)

完整的错误是:

mscorlib.dll中出现"System.OutOfMemoryException"类型的异常,但未在用户代码中处理

该机器运行64位窗口,内存为16Gb.

那么,我的选择是什么?

我想要的只是IQueryable<MyObject>一个(非常大的)JSON字符串.

Pan*_*vos 8

您的代码基本上模拟了StreamReader.ReadToEnd所做的事情,至少占用了读取大响应所需内存的4倍(字符串响应本身的内存,StringBuilder的内部缓冲区,所有中间临时字符串的大小和最终字符串) .

您可以通过使用JsonTextReader直接从流中反序列化来避免这种情况.从文档示例中复制:

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

Ø