【问题标题】:Json.Net throws OutOfMemoryException only in Visual StudioJson.Net 仅在 Visual Studio 中抛出 OutOfMemoryException
【发布时间】:2016-06-05 13:16:48
【问题描述】:

我有一些奇怪的行为,我无法弄清楚。

我正在使用 WCF 服务将文件保存到某个数据库表。 WCF 服务有一个将 JSON 字符串作为参数的方法。在这种情况下,JSON 是一个序列化命令,其中包含 List<FileData> 以及其他属性。 WCF 服务反序列化 JSON 并为此特定命令运行 CommandHandler

最终用户在尝试上传大小为 52 MB 的文件时遇到了错误。 WCF 服务返回 404 错误。

我能够在 Visual Studio 中重现这一点。按照这个article修改配置文件后,404就消失了。

但是现在出现了一个新的异常:当命令成功序列化客户端,被 WCF 成功处理时,反序列化抛出一个OutOfMemoryException。这是堆栈跟踪的顶部:

在 Newtonsoft.Json.JsonTextReader.ReadData(Boolean append, Int32 charsRequired) 在 Newtonsoft.Json.JsonTextReader.ReadData(布尔附加) 在 Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(字符引用) 在 Newtonsoft.Json.JsonTextReader.ParseString(字符引用) 在 Newtonsoft.Json.JsonTextReader.ParseValue() 在 Newtonsoft.Json.JsonTextReader.ReadInternal() 在 Newtonsoft.Json.JsonReader.ReadAsBytesInternal() 在 Newtonsoft.Json.JsonTextReader.ReadAsBytes() 在 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)

我写了一个单元测试来证明这个错误。但无论如何,这个测试通过了,换句话说,没有OutOfMemoryException被抛出。

为了完整性而进行的测试:

    [TestMethod]
    public void LoadBigFile_SerializeDeserialize_DoesntThrowOutOfMemoryException()
    {
        // Arrange
        byte[] bytes = new byte[80000000];
        Random r = new Random(23);
        r.NextBytes(bytes);

        var command = new SomeCommand(new List<FileData>
        {
            new FileData(
                fileFullName: @"D:\SomePdfFile.pdf",
                modifyDate: DateTime.MaxValue,
                data: bytes
                )
        });

        var data = JsonConvert.SerializeObject(command);

        // Act
        var deserializedCommand = 
              JsonConvert.DeserializeObject<SomeCommand>(data);

        // Assert
        Assert.AreEqual(bytes.Length, deserializedCommand.Files.First().Data.Length);
    }

所以,我抓住机会更改了生产环境中的配置文件并尝试上传相同的文件。那就行了!!!没有OutOfMemoryException

现在我的问题是,为什么OutOfMemoryException 只发生在 Visual Studio 中,而同一 VS 实例中的单元测试却没有?感觉有点奇怪,我无法在 Visual Studio 中测试上传大文件,而它在生产中工作。请注意,我还尝试像在发布模式下一样在调试中运行。

一些细节:

  • 使用 Json.Net 7.0.1
  • Visual Studio 2015,更新 2
  • WCF 在本地托管在 IIS Express 中,在生产环境中托管 IIS
  • Windows 10 最新版本 64 位
  • 生产服务器 Windows server 2008 R2 64 位
  • .Net Framework 4.5.2

【问题讨论】:

  • 您的本地开发机器是 32 位还是 64 位?这与部署服务器不同吗?您的配置是“任何 CPU”吗?
  • @mellamokb:我的开发机器和服务器都是 64 位的。

标签: c# visual-studio-2015 json.net deserialization


【解决方案1】:

我通过将byte[] bytes = new byte[80000000]; 更改为byte[] bytes = new byte[52000000]; 并循环运行(2 次),在单元测试中复制了OutOfMemoryException。测试运行器是 32 位的。

回到 IIS Express - 我认为您使用的是 32 位版本。您可以在

处更改此设置

工具 |选项 |项目和解决方案 |网站项目 |使用 64 位版本的 IIS Express

【讨论】:

  • 像魅力一样工作!谢谢,从来不知道 IIS 默认运行在 32 位上,一直以为它遵循构建的配置。
  • 顺便说一句 - 80MB 有什么问题?它甚至没有接近 2GB 的限制
  • @Royi,原来这样的对象在序列化/反序列化时,内存消耗远超80MB
  • @Royi,是的,它仍然可以用 Json.net 10 重现。它一定也与测试运行器/视觉工作室有关。但不管单元测试如何,也可以用220MB数组的控制台应用(32位)重现
  • 3 年半后,你用这个答案救了我。谢谢。
猜你喜欢
  • 1970-01-01
  • 2015-02-28
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2013-03-08
  • 2016-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多