草庐IT

c# - 是否有一个 .Net 内存分析器可以跟踪大对象堆上的所有分配?

coder 2024-05-22 原文

关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。












想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。

3年前关闭。




Improve this question




我尝试过的大多数 .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。然而,在这段时间里,私有(private)字节通过屋顶,翻了一番,翻了三番,而我实际分配的对象(在所有堆上)的大小只略有增加。例如,所有堆中的字节为 115MB,但我的私有(private)字节超过 512 MB。

ANTS 清楚地告诉我,我遇到了内存碎片问题。结果我在 LOH 上创建了短暂的对象。但是,这些对象的总大小不会超过 3 或 4 MB。所以这些短命的大物体(似乎?)正在 split LOH。

回应 Eric Lippert 和迪士尼乐园 parking 场的比喻(这很棒)。

这就像有人在一个地方 parking 几分钟,然后离开。然后保留该位置(没有其他人可以在那里 parking ),直到我重新铺设 parking 场!

当 Visual Studio 警告我内存使用情况并建议切换到 x64 时,我首先开始对此进行调查。 (我忘记了警告号码,快速谷歌没有找到)。因此,切换到 x64 可以缓解眼前的问题,但并没有解决根本问题。

就像我有一个可以停 1000 辆车的 parking 场,但是当我把 100 辆车放进去之后,我的 parking 服务员尖叫着说它已经满了......

幸运的是,我有一个庞大的 VMware 集群可供我使用,并且有一个懂行的管理员。我被分配了 8 个 cpu 和 8 GB 的内存。所以只要有问题,我可以处理,我只是投入资源。另外,(正如我上面所说的)我切换到 x64 一段时间,因为 Visual Studio 不断提醒我警告,但是,我想弄清楚它在 LOH 上分配的内容,看看我是否可以减轻这种堆碎片一些小的代码更改。也许是一个傻瓜的差事,因为我可以向它扔资源。

应用程序运行良好,速度很快,偶尔会出现 GC 暂停。但大多数情况下我可以忍受这种情况,我只想知道是什么物体导致了它。我的怀疑是一些我还没有找到的短期字典。

编辑3 :http://msdn.microsoft.com/en-us/magazine/cc188781.aspx

ObjectAllocatedByClass does not track allocations of the large object heap, but ObjectAllocated does. By comparing the notifications from the two, an enterprising soul should be able to figure out what is in the large object heap as opposed to the normal managed heap.



所以看起来这是可以做到的。但是,我的 C++ 技能很难深入研究(如果我有更多时间,可能在 future 某个时候)。我希望分析器能够提供这种开箱即用的功能。

最佳答案

经过试验,我能够在 GC 从一代中删除事物时收到通知,但在将其放入时却无法收到通知。

由于 LOH 不是特定于世代的,并且没有我可以访问的特定事件以获取 LOH 插入的通知,因此我可以提供的唯一替代方法是调试应用程序,进行故障转储 - 或者 - 在本地运行它并使用 WinDBG。您可以这样做:

  • 下载 Windows SDK 7
  • 将 %Microsoft_NET_Framework%\sos.dll 复制到 WinDBG 目录
  • 在 WinDBG 中单击文件 -> 打开可执行文件 -> 指向您的可执行文件
  • 在底部的命令栏中键入 g (去)
  • 监控内存,当你想分析它时,去 WinDBG -> 调试菜单 -> 中断
  • 类型 load .sos - 加载 .NET 扩展
  • 类型 !dumpheap -min 85000 - 这将列出应位于 LOH
  • 上的大型对象

             Address               MT     Size
    0000000012a17048 000007fee7ae6ae8   400032     
    0000000012a78b00 000007fee7ae6ae8   400032     
    0000000012ada5b8 000007fee7ae6ae8   400032     
    0000000012b3c070 000007fee7ae6ae8   400032     
    0000000012b9db28 000007fee7ae6ae8   400032
    


    接下来,我们需要逐一检查并找出其中的内容。
  • 将第一列(对象地址)复制到剪贴板
  • 类型 !do <paste from clipboard>
  • 这将列出对象的内容、类型和大小。

  • CLR Version: 4.0.30319.261
    SOS Version: 4.0.30319.239
    Name:        System.String
    MethodTable: 000007fee7ae6ae8
    EEClass:     000007fee766ed68
    Size:        400026(0x61a9a) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:      8470737076787475867884758166807183888774746571677189..
    Fields:
                  MT    Field   Offset                 Type VT     Attr            Value Name
    000007fee7aec9d0  4000103        8         System.Int32  1 instance           200000 m_stringLength
    000007fee7aeb510  4000104        c          System.Char  1 instance               38 m_firstChar
    000007fee7ae6ae8  4000105       10        System.String  0   shared           static Empty
                                     >> Domain:Value  000000000055fe50:0000000002a11420 <<
    


    您要查找的行是:

    Size:        400026(0x61a9a) bytes
    String:      8470737076787475867884758166807183888774746571677189..
    

  • 为每个对象执行此操作

  • (但是,我假设它是一个字符串,因此请查看 'Name' 属性以确保它。它可能是一个数组。)

    关于c# - 是否有一个 .Net 内存分析器可以跟踪大对象堆上的所有分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9911788/

    有关c# - 是否有一个 .Net 内存分析器可以跟踪大对象堆上的所有分配?的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    3. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

      给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

    4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

      使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

    5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

      我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

    6. ruby-on-rails - 渲染另一个 Controller 的 View - 2

      我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

    7. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

      查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

    8. ruby - 如何模拟 Net::HTTP::Post? - 2

      是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

    9. ruby - 检查数组是否在增加 - 2

      这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

    10. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

      我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

    随机推荐