- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我们在 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 毫秒。
我有两个问题:
--
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/
具有大量项目的.NET集合是否易于存储在LOH中? 我对列表和字典特别好奇。在我的代码中,我将大量(40k +)相对较小的对象(比如说1k)存储在临时列表和字典中以进行处理。这些收藏中的物品数量是否会
我有几百个 的实例我的类 存在于托管堆中。其中一些位于大对象堆中。下面是各种堆结构的样子 0:000> !EEHeap -gc Number of GC Heaps: 1 generation 0 s
在我的应用程序中,我需要将大文件(大约 250 MB)加载到内存中,我以一种惰性的方式进行——当用户要求查看文件时——我正在加载它。之后,每次用户尝试访问该文件时,我都能立即显示它,因为它已经位于内存
我们在 Server 2012 上有一个使用 WebApi 2、.NET 4.5 的 Web 服务。我们发现延迟偶尔会无缘无故地增加 10-30 毫秒。我们能够将有问题的代码片段追踪到 LOH 和 G
在与一位同事谈论一组特定的应用程序在启动时使用近 1.5G 内存时...他向我指出了一个很好的链接 .NET production debugging 让我困惑的部分是...... For examp
看了一些关于.Net/C#/CLR等的帖子和书籍,在微软2005年的presentation中找到了如下幻灯片: GC takes time – “% time in GC” counter If o
有很多关于 .NET LOH 的可用信息,并且已经在各种文章中进行了解释。但是,似乎有些文章不够精确。 过时信息 在Brian Rasmussen's answer (2009), program m
我正在使用下面的代码将大文件上传到服务器,并注意到将 FileStream 复制到 GetRequestStream 会创建字节数组并将其保存在内存中。这增加了大对象堆,我不想要它。也许有人知道如何解
我还有一个 Unresolved 问题 HERE关于一些可能涉及 LOH 碎片以及其他未知数的绝望内存问题。 我现在的问题是,公认的做事方式是什么?如果我的应用程序需要在 Visual C# 中完成,
我有一个类负责在下载管理器中下载文件。该类负责下载文件并将其写入给定路径。 要下载的文件大小通常在 1 到 5 MB 之间,但也可能更大。我正在使用 WebClient 类的实例从 Internet
我读到,在托管堆中固定对象会影响 .NET 中的 GC 性能,因为如果“妨碍”固定对象,GC 就无法压缩内存。但由于大型对象堆无论如何都不会被压缩,因此这不适用于 LOH 中的对象。固定 LOH 中的
我有一个 OData 响应作为 JSON (只有几 MB) 并且要求流式传输“JSON 的某些部分”,甚至不将它们加载到内存中。 例如:当我读取以下 JSON 中的属性“value[0].Body.C
已开发的新应用程序大量使用 Web 服务。我们开始定期遇到内存不足异常(随着使用量的增加)。在查看内存转储时,我注意到有大量相同大小的 byte[]。查看这些 byte[] 的句柄,我注意到它们被 S
好吧,这是我第一次尝试对 .NET 应用程序进行内存分析(我已经完成了 CPU 调整),但我在这里遇到了一些困难。 我的应用程序中有一个 View ,每页加载 40 张图片(最多),每张图片约 3MB
我是一名优秀的程序员,十分优秀!