Json.Net反序列化内存不足问题

时间:2015-11-02 14:55:59

标签: c# json.net base64 out-of-memory

我有一个Json,其中包含一个存储base64编码字符串的数据字段。 这个Json被序列化并发送给客户。

在客户端,newtonsoft json.net反序列化器用于返回Json。 但是,如果数据字段变大(~400 MB),则解串器将抛出内存不足异常:数组维度超出支持的范围。 我还在Task-Manager中看到,内存消耗确实快速增长。

为什么会这样?是否有json字段的最大大小?

代码示例(简化):

HttpResponseMessage responseTemp = null;
responseTemp = client.PostAsJsonAsync(client.BaseAddress, message).Result;

string jsonContent = responseTemp.Content.ReadAsStringAsync.Result;
result = JsonConvert.DeserializeObject<Result>(jsonContent);

结果类:

public class Result
{

    public string Message { get; set; }
    public byte[] Data { get; set; }

}

更新

我认为我的问题是不是序列化程序,而只是试图在内存中处理这么大的字符串。 在我将字符串读入内存时,应用程序的内存消耗会爆炸。该字符串上的每个操作都是相同的。目前,我认为我必须找到一种处理流的方法,并立即停止将所有内容读入内存。

3 个答案:

答案 0 :(得分:13)

使用JsonConvert.DeserializeObject读取大型JSON字符串将消耗大量内存。因此,可以通过以下方式创建JsonSerializer实例。

 using (StreamReader r = new StreamReader(filePath))
 {
          using (JsonReader reader = new JsonTextReader(r))
         {
                JsonSerializer serializer = new JsonSerializer();
                T lstObjects = serializer.Deserialize<T>(reader);
        }
}

此处 filePath : - 是您当前的Json文件和 T : - 是您的通用类型对象。

答案 1 :(得分:5)

我假设您使用的是64位。如果没有,switch

完成此操作后,如果您使用.Net 4.5或更高版本,请启用gcAllowVeryLargeObjects。它允许具有最多int.MaxValue个条目的数组,即使这会导致底层内存缓冲区大于2 GB。您仍然无法读取长度超过2 ^ 31个字符的单个JSON令牌,但是,因为JsonTextReader缓冲了private char[] _chars;中每个令牌的全部内容}数组,和.Net,an array can only hold up to int.MaxValue items

答案 2 :(得分:2)

巨大的base64字符串不是一个问题,.Net支持大约2gb的对象大小,请参阅答案here。 当然,这并不意味着您可以在对象中存储2gb的信息!

然而,我觉得它是问题的字节[]。

如果包含的字节[]包含的元素太多,那么如果您流式传输结果甚至从硬盘驱动器上的文件中读取结果都无关紧要。

因此,出于测试目的,您是否可以尝试将其类型从byte []更改为字符串甚至可能是List? 它不优雅或事件可能是可取的,但它可能指向更好的解决方案。

修改

尝试的另一个测试用例,而不是调用deserializeObject,尝试将jsonContent字符串保存到文件中,看看它有多大?

另外,为什么你需要它在内存中?它是什么类型的数据? 在我看来,如果你必须在内存中处理这个问题,那么你将会遇到一个糟糕的时间 - 对象的大小对于CLR来说太大了。

然而,只是有一点灵感,尝试不同的解串器怎么样?也许RestSharp或您可以使用HttpClient.ReadAsAsync<T>。有可能它的NewtonSoft本身存在问题,特别是如果内容的大小约为400mb。