【发布时间】:2012-04-12 07:08:47
【问题描述】:
我尝试过的大多数 .NET 内存分析器都允许您拍摄内存快照。
但是,我正在尝试诊断一个问题,即最终分配给 .NET 的大量内存被 ANTS 分析器指示为“空闲”。 (我已经用 Mem Profiler 和 CLR profiler 等其他分析器确认了这个问题。
ANTS 显示我有大量内存碎片(100% 的可用内存,最大块为 150MB。)堆中所有对象的总大小为 180MB。我有 553 MB 分配给 .NET,152 MB 分配给“非托管”。
但是,大对象堆 (LOH) 的大小仅为 175kb。这是那里分配的对象的实际大小。我不会永久分配最终在 LOH 上的任何对象。
因此,我的问题是,在某些地方,我怀疑我以某种方式分配了大型对象(超过 LOH 的 85k 限制)然后处置它们。
我正在从数据库(Oracle、Sql Server)中读取大量数据(此处估计为数 MB),将这些数据复制到内存中的对象数组,并将数据处理为索引(数组、字典等)更容易搜索/过滤/处理。
我的猜测是,数据读取器暂时分配了大量空间。但是,我没有一个很好的方法来暂停程序并拍摄内存快照。
我想要的是一个分析器,它可以跟踪 LOH 上分配的每个对象,这样我就可以找出导致 LOH 碎片和过多内存使用的原因(内存没有返回到操作系统,所以看起来我的进程需要 1GB 的内存来存储 200MB 的分配对象。)我猜内存没有返回,因为 LOH 没有被压缩,所以我一辈子都被这些内存卡住了我的进程,可能是几周(它作为 Windows 服务运行。)
编辑:我的问题是我的 .NET 应用程序使用了大量我无法追踪的内存。
Edit1:我使用了 Visual Studio 内存分析器。虽然它确实告诉我所有实例化的对象、有多少、总字节数等,但我没有提示我为什么最终会得到这么多可用内存。我唯一的提示/线索是 ANTS 告诉我的内容:“内存碎片限制了可以分配的对象的大小。”而且我有很多未使用的分配给 .NET 的未使用内存。
Edit2:更多分析显示我在 LOH 上分配了一些短暂的大对象。但是,在 LOH 上分配的总量永远不会超过 3 到 4 MB。然而,在这段时间里,私有字节猛增一倍和三倍,而我实际分配的对象(在所有堆上)的大小仅略有增长。例如,所有堆中的字节为 115MB,但我的私有字节超过 512 MB。
ANTS 清楚地告诉我,我遇到了内存碎片问题。原来我在 LOH 上创建了短暂的对象。但是,这些对象的总和永远不会超过 3 或 4 MB。所以这些短命的大物体(看起来像?)正在将 LOH 分解成碎片。
回应 Eric Lippert 和迪斯尼乐园停车场的类比(这很棒)。
就像有人在某个地方停了几分钟,然后就离开了。然后保留那个位置(没有其他人可以在那里停车),直到我重新铺设停车场!
当 Visual Studio 警告我内存使用情况并建议切换到 x64 时,我开始对此进行调查。 (我忘记了警告号码,快速谷歌没有找到它)。所以切换到 x64 可以缓解眼前的问题,但不能解决根本问题。
就像我有一个可以停 1000 辆汽车的停车场,但是当我把 100 辆汽车放进去后,我的停车服务员却在尖叫它已经满了……
幸运的是,我有一个庞大的 VMware 集群可供我使用,并且管理员很了解。我被分配了 8 个 CPU 和 8 GB 内存。所以就问题而言,我可以处理它,我只是向它投入资源。此外,(正如我上面所说)我切换到 x64 一段时间,因为 Visual Studio 一直在提醒我警告但是,我想弄清楚它在 LOH 上分配了什么,看看我是否可以减轻这个堆碎片一些小的代码更改。考虑到我可以为此投入资源,这可能是愚蠢的差事。
应用程序运行良好,速度很快,偶尔会出现 GC 暂停。但大多数情况下我可以忍受这种情况,我只想知道是什么物体造成的。我的怀疑是一些我还没有找到的短命字典。
Edit3:http://msdn.microsoft.com/en-us/magazine/cc188781.aspx
ObjectAllocatedByClass 不跟踪大对象的分配 堆,但 ObjectAllocated 可以。通过比较来自的通知 二、有进取心的人应该能猜出里面是什么 大型对象堆,而不是普通托管堆。
所以看起来这个可以完成。但是,我的 C++ 技能很难深入研究(如果我有更多时间,可能会在未来某个时候)。我希望探查器能提供开箱即用的功能。
【问题讨论】:
-
您的应用程序是否使用字符串实习?
-
那么具体是什么问题?是你的虚拟内存用完了,还是工作集太大而你正在破坏页面文件,还是什么?
-
@EricLippert 问题是我的应用程序占用了内存,我不知道为什么。
-
使用大量内存的应用程序本身不是问题;很明显,这是一个关注。但是,如果您有足够的虚拟内存并且没有破坏磁盘,那么使用用户会注意到的大量内存并没有实际的问题。只解决你实际遇到的问题。
-
在我的例子中,将应用程序置于 GCServer 模式会导致为 .NET 分配大量“可用空间”。原因是 gcserver 模式为每个逻辑处理器创建堆。我有 8 个逻辑处理器,因此 .NET 框架将数据分配到 8 组堆上,我确信这会导致“过度分配”,等等。一旦我关闭 gcserver 模式,就会发生更少的“过度分配”。
标签: c# .net memory-management memory-leaks