Chr*_*ber 15 .net c# memory-leaks memory-management
我尝试过的大多数.NET内存分析器都允许您拍摄内存快照.
但是,我正在尝试诊断一个问题,即我最终将大量内存分配给.NET,并由ANTS分析器指示为"免费".(我已经与Mem Profiler和CLR分析器等其他分析器确认了这个问题.
ANTS显示我有大量的内存碎片(100%的可用内存,150MB作为最大的块.)堆中所有对象的总大小为180MB.我有553 MB分配给.NET和152分配给"Unmanaged".
但是,大对象堆(LOH)的大小仅为175kb.这是在那里分配的对象的实际大小.我没有永久地分配任何最终在LOH上的对象.
因此,我的问题,一些沿线,我怀疑我以某种方式分配大对象(超过85K的LOH限制),然后处置它们.
我正在从数据库(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 就在问题中 - 我知道我错了 - 但这里是:-)
LOH 只会存储大小大于 85k 的特定对象。我根据经验发现,这通常是字符串 - XML 或全局变量和/或静态变量中的大型可枚举类型。
如果您的 LOH 很小,您必须在内存中存储其他对象,这些对象很可能最终成为第 2 代。这些对象可能是全局变量,例如数组、字典等整个应用程序生命周期中的变量。
因此,要快速检查的第一件事是检查在应用程序的整个生命周期中是否存在任何变量?这些有数千个条目吗?
其次,.NET 对每一代大小的内存大小都有性能计数器统计。计数器可以直接指向应用程序,因此这将是一个很好的下一步。
最后,GC 仅在需要时才会清除内存。所以是的,如果 GC 觉得不需要(内存压力方面)清除任何东西,它可能会保持相同的大小。您可以强制进行垃圾收集,但通常建议让 GC 完成其工作。
我问了一个类似的问题,为什么字符串在我的应用程序中存储了这么长时间。我使用 WinDBG 来分析我通过转到“任务管理器”->“进程”->“右键单击”->“创建故障转储”强制生成的故障转储。然后将其加载到 WinDBG (Windows SDK 7) 中。
希望该链接能为您提供更多指导来追踪问题的根源(双关语)。
还有一个问题回到OP:这是否会严重影响您的服务器,或者您只是好奇为什么内存会残留?
| 归档时间: |
|
| 查看次数: |
6244 次 |
| 最近记录: |