草庐IT

c# - .NET 内存加载约 40 张图像时出现问题,内存未回收,可能是由于 LOH 碎片

coder 2023-07-10 原文

好吧,这是我第一次尝试对 .NET 应用程序进行内存分析(我已经完成了 CPU 调整),但我在这里遇到了一些困难。

我的应用程序中有一个 View ,每页加载 40 张图片(最多),每张图片约 3MB。页面的最大数量是 10。鉴于我不想一次保留 400 张图像或 1.2GB 的内存,我在页面更改时将每个图像设置为空。

现在,起初我以为我一定只是对这些图像有过时的引用。我下载了 ANTS 分析器(很棒的工具 BTW)并运行了一些测试。对象生命周期图告诉我,除了父类中的单个引用之外,我没有对这些图像的任何引用(这是设计使然,也通过仔细梳理我的代码确认):

父类 SlideViewModelBase 永远留在缓存中,但是当页面更改时 MacroImage 属性设置为 null。我没有看到任何迹象表明这些元素应该比预期保存更长时间。

接下来我大致了解了大对象堆和内存使用情况。查看三页图像后,我在 LOH 上分配了 691.9MB 的非托管内存和 442.3MB。 System.Byte[],它来 self 的 System.Drawing.BitmapBitmapImage 的转换几乎占用了所有 LOH 空间。这是我的转换代码:

public static BitmapSource ToBmpSrc( this Bitmap b )
{
    var bi = new BitmapImage();
    var ms = new MemoryStream();
    bi.CacheOption = BitmapCacheOption.OnLoad;
    b.Save( ms,  ImageFormat.Bmp );
    ms.Position = 0;
    bi.BeginInit();
    ms.Seek( 0, SeekOrigin.Begin );
    bi.StreamSource = ms;
    bi.EndInit();
    return bi;
}

我很难找到所有非托管内存的去向。一开始我怀疑是 System.Drawing.Bitmap 对象,但 ANTS 并没有显示它们在附近,而且我还进行了一次测试,我绝对确保所有这些对象都被处理掉了,但它没有。不会有什么不同。所以我还没有弄清楚所有这些非托管内存是从哪里来的。

我目前的两个理论是:

  1. LOH 碎片化。如果我离开分页 View 并单击几个按钮,大约有一半的 ~1.5GB 被回收。仍然太多,但仍然很有趣。
  2. 一些奇怪的 WPF 绑定(bind)东西。我们确实使用数据绑定(bind)来显示这些图像,我不是这些 WPF 控件工作原理的专家。

如果有人有任何理论或分析技巧,我将非常感激(当然)我们的截止日期很紧,我正在争先恐后地完成最后一部分并开始工作。我想我已经被跟踪 C++ 中的内存泄漏给宠坏了……谁会想到?

如果您需要更多信息或希望我尝试其他方法,请询问。抱歉这里的文字墙,我尽量保持简洁。

最佳答案

blog post似乎描述了您所看到的,建议的解决方案是创建一个 implementation of Stream that wraps another stream .

这个包装类的 Dispose 方法需要释放包装流,以便它可以被垃圾收集。一旦使用此包装流初始化 BitmapImage,就可以释放包装流,释放底层流,并允许释放大字节数组本身。

The BitmapImage keeps a reference to the source stream so it keeps the MemoryStream object alive. Unfortunately, even though MemoryStream.Dispose has been invoked, it doesn't release the byte array that the memory stream wraps. So, in this case, bitmap is referencing stream, which is referencing buffer, which may be taking up a lot of space on the large object heap. There isn't a true memory leak; when there are no more references to bitmap, all these objects will (eventually) be garbage collected. But since bitmap has already made its own private copy of the image (for rendering), it seems rather wasteful to have the now-unnecessary original copy of the bitmap still in memory.

另外,您使用的是什么版本的 .NET?在 .NET 3.5 SP1 之前,有一个已知问题 BitmapImage could cause a memory leak .解决方法是调用 Freeze在 BitmapImage 上。

关于c# - .NET 内存加载约 40 张图像时出现问题,内存未回收,可能是由于 LOH 碎片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6271891/

有关c# - .NET 内存加载约 40 张图像时出现问题,内存未回收,可能是由于 LOH 碎片的更多相关文章

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

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

  2. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  3. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. 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

  6. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  7. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  8. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  9. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  10. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

随机推荐