我们有一个托管的 .Net/C# 应用程序,它创建 TPL 任务以对 JPEG 图像执行 JPEG 元数据编码。每个任务都使用 TaskCreationOptions.LongRunning 选项构建,例如,
Task task = new Task( () => TaskProc(), cancelToken, TaskCreationOptions.LongRunning );
TaskProc() 利用 JpegBitmapDecoder 和 JpegBitmapEncoder 类添加 JPEG 元数据并将新图像保存到磁盘。 我们允许最多 2 个这样的任务在任何时候处于事件状态,并且这个过程应该无限期地继续下去。
执行上述操作一段时间后,我们得到 没有足够的可用存储空间 尝试创建 JpegBitmapDecoder 类的实例时处理此命令异常:
System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int3 2 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHoo k[] hooks) at System.Windows.Threading.Dispatcher..ctor() at System.Windows.Threading.Dispatcher.get_CurrentDispatcher() at System.Windows.Media.Imaging.BitmapDecoder..ctor(Stream bitmapStream, BitmapC reateOptions createOptions, BitmapCacheOption cacheOption, Guid expectedClsId) at System.Windows.Media.Imaging.JpegBitmapDecoder..ctor(Stream bitmapStream, Bit mapCreateOptions createOptions, BitmapCacheOption cacheOption)
当我们使用 JpegBitmapDecoder 添加元数据时,仅发生错误。换句话说,如果任务只是编码位图图像并将其保存到文件中,则不会出现任何问题。使用 Process Explorer、Process Monitor 或其他诊断工具时,没有发现任何明显的问题。根本没有观察到线程、内存或句柄泄漏。出现此类错误时,无法启动新的应用程序,例如记事本、word 等。 一旦我们的应用程序终止,一切都会恢复正常。
LongRunning 的任务创建选项在 MSDN 中定义为 指定任务将是长时间运行的粗粒度操作。它向 TaskScheduler 提示可能需要超额订阅。 这意味着选择运行任务的线程可能不是来自 ThreadPool,即,它将为任务的目的而创建。其他任务创建选项将导致为任务选择 ThreadPool 线程。
经过一段时间的分析和测试,我们将任务创建选项更改为 LongRunning 以外的任何选项,例如 PreferFairness。根本没有对代码进行任何其他更改。这“解决”了问题,即不再出现存储空间不足的错误。
我们对 LongRunning 线程成为罪魁祸首的真正原因感到困惑。 以下是我们对此提出的一些问题:
为什么选择执行任务的线程应该来自线程池?如果线程终止,它的资源是否应该随着时间的推移由 GC 回收并返回给操作系统,而不管它的来源?
导致错误的 LongRunning 任务和 JpegBitmapDecoder 功能的组合有什么特别之处?
最佳答案
System.Windows.Media.Imaging 命名空间中的类基于 the Dispatcher threading architecture .无论好坏,默认行为的一部分是在任何线程正在执行的任何线程上启动一个新的 Dispatcher,只要某个组件通过静态 Dispatcher.Current 属性请求当前调度程序。这意味着为线程启动了整个 Dispatcher“运行时”,并且分配了各种资源,如果没有正确清理,将导致托管泄漏。 Dispatcher“运行时”还期望其执行的线程是一个 STA 线程,标准消息泵正在进行,而 Task 运行时默认情况下不会启动 STA 线程.
所以,综上所述,为什么它会发生在 LongRunning 而不是基于“常规”ThreadPool 的线程上?因为 LongRunning 意味着您每次都在启动一个新线程,这意味着每次都有新的 Dispatcher 资源。最终,如果您让默认任务调度程序(基于 ThreadPool 的调度程序)运行足够长的时间,它也会耗尽空间,因为没有为 Dispatcher 运行时发送消息以清理它需要的东西
因此,如果您想像这样使用基于 Dispatcher 的线程类,您确实需要使用旨在运行此类任务的自定义 TaskScheduler在正确管理 Dispatcher“运行时”的线程池上工作。好消息是你很幸运,因为我已经写了一个 you can grab here . FWIW,我在每天处理数十万张图像的生产代码的三个非常大的部分中使用此实现。
实现更新
我最近再次更新了实现,以便它与 .NET 4.5 的新 async 功能兼容。原始实现不与 SynchronizationContext 概念合作,因为它不必如此。既然您可能在 C# 中的 Dispatcher 线程上执行的方法中使用 await 关键字,我需要能够与之合作。在这种情况下,以前的实现会陷入僵局,而最新的实现不会。
关于c# - 为什么使用 JpegBitmapDecoder 的 LongRunning 任务 (TPL) 会耗尽资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12624867/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类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
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t