使内存密集型后台应用程序“友好”
Posted
技术标签:
【中文标题】使内存密集型后台应用程序“友好”【英文标题】:Making a memory intensive background application "friendly" 【发布时间】:2010-12-09 19:36:13 【问题描述】:我有一个应用程序需要定期使用计算量不大的算法处理大块数据。事实证明,我还可以通过将数据块保存在内存缓存中来防止系统因硬盘访问而变慢。该应用程序是一个低优先级应用程序,因此我正在努力将其对整个系统的影响降至最低,这意味着使用额外的内存(如果可用)来减少 CPU 和硬盘驱动器的负载。缓存的数据只有 64MB 字节块,内存中的数据越多,程序在驱动器上的开销就越少。
我需要做的是在系统上的任何其他应用程序需要比可用物理内存更多的物理内存时转储内存缓存,并且速度足够快,以至于用户永远不会因为高内存需求而感到系统变慢。
我对如何在 .NET 应用程序中实现这一点特别感兴趣。
【问题讨论】:
【参考方案1】:一种选择是使用 ASP.NET 缓存,它会清除项目以响应低内存。虽然 Microsoft 附加了一个重大警告,即它仅在 ASP.NET 应用程序中进行测试,但没有什么可以阻止您在任何应用程序中访问 HttpRuntime.Cache
,实际上,当我这样做时它已经工作了。
如果这感觉很肮脏和错误(或者只是不能完全满足您的需要),我们至少可以从 ASP.NET 知道如何清除缓存中汲取灵感。它定期调用内核的GlobalMemoryStatusEx 来查找可用内存。具体来说,返回结构的 dwMemoryLoad 属性是正在使用的总内存的百分比。默认情况下,当达到 90% 时,ASP.NET 认为内存已用完。
有一些示例代码可以自己调用here。
【讨论】:
它只感觉“肮脏和错误”,因为我正在最大限度地减少应用程序引用的程序集的数量。我会查看您提到的 API - 我认为在低优先级线程上进行定期轮询可以满足我的需求,特别是如果我通过当前值及其导数以及当前 CPU 使用率来预测内存需求。 【参考方案2】:您可以使用 LowMemoryResourceNotification 选项 P/Invoke 到 Win32 CreateMemoryResourceNotification API。这将返回一个通知对象,您可以轮询(使用 QueryMemoryResourceNotification)或等待(在后台线程中;您需要使用 Win32 等待方法之一而不是 .NET 等待方法,或者可能从WaitHandle 封装 Win32 对象)。您将通过从缓存中删除块并强制进行垃圾收集来做出响应;您必须测试这是否“足够快,以至于用户永远不会感觉到系统变慢”。
此外,查看文档,发出低内存通知的阈值是真的低内存(在 4 GB 系统上为 32 MB!)。我怀疑到那时用户可能已经感觉到速度变慢了,将您的应用程序分页到内存中以转储其块可能会导致可察觉的磁盘访问。同样,您可以通过测试对此进行评估。
【讨论】:
这是一个有趣的想法,但正如您所提到的,看起来我需要比提供的更多通知。提到从SafeWaitHandle
派生的处理内存块的新类型,您将获得 +1。
其他人试过这个看看它是否真的有效?当我尝试使用 QueryMemoryResourceNotification 时,我从未收到通知 - 即使进程因等待分配内存而挂起。【参考方案3】:
您可以使用 WeakReference 类对内存块进行弱引用。这允许垃圾收集器在必要时删除对象。
Yor 对象将位于大对象堆中,因为它们大于 85 kb。最常见的垃圾收集只查看第一代堆,因此它不会收集您的对象。如果系统通知 .NET 系统内存不足,垃圾收集器将运行更彻底的收集,删除大对象堆中的对象。
【讨论】:
为什么投反对票?如果你不评论你不喜欢的东西,那是毫无意义的。 这并不能解决其他应用程序的内存需求,并且它过多地依赖于我何时/何地有一个正常的引用或只是对缓存项的弱引用。即使我正在积极处理其中一个块,我也需要处理内存问题。 @Guffa:我投了所有的票,然后投了我的 cmets - 抱歉耽搁了。我同意,没有解释的投票是无用且令人恼火的。 @280Z28:为什么你认为它不能满足其他应用程序的内存需求?如果系统不知道这些需求,你怎么可能发现它们呢?而且我不明白你在处理块时处理内存问题的意思......你想中止当前的处理吗? 是的,它会停止处理,几分钟后会检查可用内存,看看是否应该再试一次。以上是关于使内存密集型后台应用程序“友好”的主要内容,如果未能解决你的问题,请参考以下文章