最初的内存使用量为4660 K,然后增加到6920 K,但最终没有减少。
演示
static void Main(string[] args)
{
string data = File.ReadAllText("./generated.json");
Console.WriteLine("Begin parsing data...");
for (var i = 0; i < 100; i++)
{
using (JsonDocument jsonDocument = JsonDocument.Parse(data))
{
}
Thread.Sleep(650);
}
Console.WriteLine("Batch task ends...");
GC.Collect();
Console.ReadLine();
}这是我的generated.json
发布于 2022-11-21 08:15:19
如果有漏洞,每个.NET Core都会注意到,因为System.Text.Json是ASP.NET核心的核心。事实上,这个问题的代码将内存消耗减少了99倍。
构建System.Text.Json命名空间中的类是为了尽可能减少分配,这不仅是为了减少内存消耗,也是为了提高速度。分配和垃圾收集缓冲区是昂贵的,特别是对于大型缓冲区。与其只为下一次调用创建一个新的类似缓冲区,不如重用缓冲区。
他们这样做的方法之一是使用池缓冲区,而不是每次分配一个新的缓冲区。JsonDocument的处置释放它使用的共享缓冲区,因此可以重用它们:
public void Dispose()
{
int length = _utf8Json.Length;
if (length == 0 || !IsDisposable)
{
return;
}
_parsedData.Dispose();
_utf8Json = ReadOnlyMemory<byte>.Empty;
if (_extraRentedArrayPoolBytes != null)
{
byte[]? extraRentedBytes = Interlocked.Exchange<byte[]?>(ref _extraRentedArrayPoolBytes, null);
if (extraRentedBytes != null)
{
// When "extra rented bytes exist" it contains the document,
// and thus needs to be cleared before being returned.
extraRentedBytes.AsSpan(0, length).Clear();
ArrayPool<byte>.Shared.Return(extraRentedBytes);
}
}
else if (_extraPooledByteBufferWriter != null)
{
PooledByteBufferWriter? extraBufferWriter = Interlocked.Exchange<PooledByteBufferWriter?>(ref _extraPooledByteBufferWriter, null);
extraBufferWriter?.Dispose();
}
}所有调用都涉及返回池的池缓冲区和对象。即使是_parsedData.Dispose(),最终调用ArrayPool.Shared.Return(数据)
public void Dispose()
{
byte[]? data = Interlocked.Exchange(ref _data, null!);
if (data == null)
{
return;
}
Debug.Assert(!_isLocked, "Dispose called on a locked database");
// The data in this rented buffer only conveys the positions and
// lengths of tokens in a document, but no content; so it does not
// need to be cleared.
ArrayPool<byte>.Shared.Return(data);
Length = 0;
}https://stackoverflow.com/questions/74515735
复制相似问题