【发布时间】:2021-02-08 23:34:05
【问题描述】:
我正在尝试反序列化通过 http Web 响应接收到的对象,并且当对象中的 byte[] 较小时它工作正常。但是当大小增加时,JsonConvert 反序列化会抛出内存异常。输入是 http web 响应而不是文件。这是在反序列化一个太大的对象。
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
return JsonConvert.DeserializeObject<SomeObjectReply<TResponse>>(streamReader.ReadToEnd());
}
}
我尝试了以下方法,但仍然是同样的问题
if (response.StatusCode == HttpStatusCode.OK)
{
using (var streamReader = new StreamReader(response.GetResponseStream()))
using (var jsonReader = new JsonTextReader(streamReader))
{
JsonSerializer serializer = new JsonSerializer();
return (SomeObjectReply<TResponse>)serializer.Deserialize(jsonReader, typeof(SomeObjectReply<TResponse>));
}
}
JSON 看起来像:
{
"Id":"81a130d2-502f-4cf1-a376-63edeb000e9f",
// The following is MUCH larger in cases where the exception is thrown.
"Document":"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8="
}
反序列化后,对象将
public class Doc
{
public Guid Id { get; set; }
public byte[] Document { get; set; }
}
即我正在反序列化具有大字节数组的单个对象。
当Document 字节数组属性变得太大时,我得到了异常:
Message: Exception of type 'System.OutOfMemoryException' was thrown.
Stack Trace:
at Newtonsoft.Json.Utilities.BufferUtils.RentBuffer(IArrayPool`1 bufferPool, Int32 minSize)
at Newtonsoft.Json.JsonTextReader.PrepareBufferForReadData(Boolean append, Int32 charsRequired)
at Newtonsoft.Json.JsonTextReader.ReadData(Boolean append, Int32 charsRequired)
at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(Char quote)
at Newtonsoft.Json.JsonTextReader.ReadAsBytes()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)
【问题讨论】:
-
如果您的 JSON 包含一个巨大的
byte []数组属性,表示为单个 base64 字符串,那么 Json.NET 将始终完全实现该字节数组,因为它始终完全实现单个属性值。我所知道的唯一可以读取块中属性值的 JSON 解析器是JsonReaderWriterFactory.CreateJsonReader()返回的读取器。使用示例见Efficiently replacing properties of a large JSON using System.Text.Json。 -
这是一个具有大字节数组的单个可反序列化对象。那个大字节数组是一个巨大的excel文件。更新了帖子,但出现了异常。
-
在这种情况下,这里有一个使用
JsonReaderWriterFactory.CreateJsonReader()解析JSON 流并将Base64 二进制流式传输到某个输出流的示例:dotnetfiddle.net/rxYuWK。那是你要的吗?这里我使用Microsoft.IO.RecyclableMemoryStream,但你可以使用FileStream。这对你有用吗?]
标签: c# json.net out-of-memory