gpt4 book ai didi

c# - 大量使用 LOH 会导致严重的性能问题

转载 作者:太空狗 更新时间:2023-10-29 21:17:17 27 4
gpt4 key购买 nike

我们在 Server 2012 上有一个使用 WebApi 2、.NET 4.5 的 Web 服务。我们发现延迟偶尔会无缘无故地增加 10-30 毫秒。我们能够将有问题的代码片段追踪到 LOH 和 GC。

我们将一些文本转换为其 UTF8 字节表示形式(实际上,我们使用的序列化库就是这样做的)。只要文本短于 85000 字节,延迟就会稳定且短:平均约为 0.2 毫秒,达到 99%。一旦超过 85000 边界,平均延迟就会增加到 ~1ms,而 99% 的延迟会跳到 16-20ms。 Profiler 显示大部分时间花在了 GC 上。可以肯定的是,如果我在迭代之间放置 GC.Collect,测得的延迟会回到 0.2 毫秒。

我有两个问题:

  1. 延迟从何而来?据我了解LOH没有压缩。 SOH 正在压缩,但未显示延迟。
  2. 是否有解决此问题的实用方法?笔记 我无法控制数据的大小并使其变小。

--

public void PerfTestMeasureGetBytes()
{
var text = File.ReadAllText(@"C:\Temp\ContactsModelsInferences.txt");
var smallText = text.Substring(0, 85000 + 100);
int count = 1000;
List<double> latencies = new List<double>(count);
for (int i = 0; i < count; i++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var bytes = Encoding.UTF8.GetBytes(smallText);
sw.Stop();
latencies.Add(sw.Elapsed.TotalMilliseconds);

//GC.Collect(2, GCCollectionMode.Default, true);
}

latencies.Sort();
Console.WriteLine("Average: {0}", latencies.Average());
Console.WriteLine("99%: {0}", latencies[(int)(latencies.Count * 0.99)]);
}

最佳答案

性能问题通常来自两个方面:分配和碎片。

分配

运行时保证干净的内存,因此花费周期清理它。当您分配一个大对象时,这会占用大量内存并开始为单个分配增加毫秒数(老实说,.NET 中的简单分配实际上非常快,所以我们通常从不关心这一点)。

当 LOH 对象被分配然后被回收时,就会发生碎片。直到最近,GC 还无法重组内存以移除这些旧对象“间隙”,因此只能在该间隙中容纳大小相同或更小的下一个对象。最近,GC 被赋予了压缩 LOH 的能力,这消除了这个问题,但在压缩过程中会花费时间。

我的猜测在您的情况下是您同时遇到问题和触发 GC 运行,但这取决于您的代码尝试在 LOH 中分配项目的频率。如果您正在进行大量分配,请尝试对象池路线。如果您无法有效地控制池( block 状对象生命周期或不同的使用模式),请尝试对您正在处理的数据进行分块以完全避免它。


您的选择

我遇到过两种处理 LOH 的方法:

  • 避免它。
  • 使用它,但意识到您正在使用它并明确管理它。

避免它

这涉及将您的大对象(通常是某种数组)分块为每个都属于 LOH 屏障的 block 。我们在序列化大对象流时这样做。运行良好,但具体实现会因您的环境而异,因此我不太愿意提供编码示例。

使用它

解决分配和碎片问题的一个简单方法是使用长生命周期对象。明确制作一个大尺寸的空数组(或数组)以容纳您的大对象,并且不要摆脱它(或它们)。保留它并像对象池一样重新使用它。您为此分配付费,但可以在首次使用时或在应用程序空闲期间执行此操作,但您为重新分配支付的费用较少(因为您没有重新分配)并减少了碎片问题,因为您不会经常要求分配东西并且您没有回收元素(这首先导致了差距)。

也就是说,中途之家可能是有序的。为对象池预留一段内存。尽早完成,这些分配在内存中应该是连续的,这样您就不会出现任何间隙,并且将可用内存的尾端留给不受控制的项目。请注意,这显然会对您的应用程序的工作集产生影响 - 无论是否使用对象池都会占用空间。


资源

LOH 在网络上有很多介绍,但请注意资源的日期。在最新的 .NET 版本中,LOH 受到了一些喜爱,并且得到了改进。也就是说,如果您使用的是旧版本,我认为网络上的资源相当准确,因为 LOH 在开始和 .NET 4.5 (ish) 之间的很长一段时间内从未真正收到任何重大更新。

比如2008年有这篇文章http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

以及 .NET 4.5 中的改进摘要:http://blogs.msdn.com/b/dotnet/archive/2011/10/04/large-object-heap-improvements-in-net-4-5.aspx

关于c# - 大量使用 LOH 会导致严重的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27381887/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com