为什么使用 JsonSerializer.DeserializeAsyncEnumerable 反序列化 1GB 文件会导致 2GB+ 内存分配?

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

我需要以流的方式反序列化一个 1GB json 文件,一次一个元素,经过一些阅读后发现

JsonSerializer.DeserializeAsyncEnumerable
可以启用此功能,同时还保持内存使用量较低。我认为这实际上意味着内存使用量的峰值不会真正超过集合中单个 json 对象的大小(对于其他进程可能会多一点)和/或大约 json 缓冲区的大小,默认情况下为 4MB(可调整) .

然而,在运行以下基准测试后

.NET 8
,结果并不是我所期望的 - 为什么在此过程中消耗了 2GB+ 内存 - 我是否严重误解了应该发生的事情😖?

[MemoryDiagnoser(true)]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[ShortRunJob]
public class DeserializationBenchmarks
{
    [Benchmark]
    public async Task StreamJsonAndDeserialize()
    {
        var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };

        var peopleJson = File.OpenRead("./peeps.json"); //1GB+ 
        var people = JsonSerializer.DeserializeAsyncEnumerable<Person>(peopleJson, options);

        await foreach (var person in people)
        {
            await Console.Out.WriteLineAsync(person.Name);
        }
        await peopleJson.DisposeAsync();
    }
}


// The json file is just an array of this simple Person object

    public class Person
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Language { get; set; }
        public string Bio { get; set; }
        public double Version { get; set; }
    }

enter image description here

我尝试过调整缓冲区大小,但没有运气,我还尝试在反序列化后将每个

person
对象清空,以确保它得到 GC(也许毫无意义) - 我希望以更多方式反序列化此文件高效记忆庄园

c# memory-management json-deserialization system.text.json benchmarkdotnet
1个回答
0
投票

老实说我不能说我知道它发生的原因,我有猜测。 也许 GC 没有启动,因为它还没有看到它的必要性,我想知道如果你在内存较低的系统中运行它会发生什么?

我有2个解决方案:

您可以使用 Cinchoo ETL,https://github.com/Cinchoo/ChoETL 一个开源的、良好的 dotnet ETL 库。然后像这样使用它:

foreach (dynamic e in new ChoJSONReader("Emp.json"))
    Console.WriteLine("Id: " + e.Id + " Name: " + e.Name);

(参考:https://github.com/Cinchoo/ChoETL/wiki/QuickJSONLoad

如果这不适用于您的用例,如何批量读取和解析 json?

© www.soinside.com 2019 - 2024. All rights reserved.