读取字符串时出现OutOfMemoryException

问题描述 投票:0回答:1

我有一个 C# .NET 系统,它采用

JSON
数据源并使用
Newtonsoft.Json.JsonConvert.DeserializeObject
转换器将其转换为对象。

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

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 但未在用户代码中处理

机器运行 64 位 Windows,内存 16Gb。

那么,我有什么选择?

我想要的只是一个(非常大的)

IQueryable<MyObject>
字符串中的
JSON

c# json rest asp.net-web-api json.net
1个回答
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>));
}
© www.soinside.com 2019 - 2024. All rights reserved.