0

我有一个应用程序:

  • 针对 C# 6
  • 目标.net 4.5.2
  • 是 Windows 窗体应用程序
  • 在 AnyCPU 模式下构建,因为它...
  • 利用无法升级到 64 位、非托管内存的旧 32 位库
  • 使用第三方控件供应商 DevExpress
  • 每天处理数 GB 的数据以生成报告

在具有许多绘图的作业中使用几个小时后,应用程序最终会耗尽内存。根据性能计数器,我花了很长时间清理代码中发现的许多泄漏,并且已经使项目处于最坏的情况下,它可能在任何给定时间使用超过 400,000K 的内存。由于数据是在锯齿状数组中处理的,因此处理此数据目前没有产生任何问题,从而防止了大对象堆的任何问题。

上次发生这种情况时,用户使用了大约 305,000K 的内存。该应用程序是如此“内存不足”,以至于错误对话框甚至无法在出现的 MessageBox 中绘制错误图标,该图标通常所在的空间全是黑色的。

到目前为止,我已经完成了以下工作来清理它:

  • Windows 窗体利用 Disposed 事件来确保清理资源,需要时手动调用 dispose
  • 业务对象利用 IDisposable 删除引用
  • 使用 ANTS 内存分析器和 SciTech 内存分析器验证清理。低内存使用表明情况并非如此,但我想看看我是否看到任何可能有帮助的东西,我不能
  • 利用 GCSettings.LargeObjectHeapCompactionMode 属性从处理大对象堆 (LoH) 中可能碎片的数据中删除任何碎片

几乎每一篇我曾经到过这一点的文章都表明内存不足实际上意味着连续的地址空间不足,并且考虑到正在使用的数量,我同意这一点。我不确定此时该做什么,因为据我了解(并且可能非常错误)是垃圾收集器会在进程进行时清除它以腾出空间,除了 LoH,它是现在使用 .net 4.5.1 中引入的新 LargeObejctHeapCompactionMode 属性手动清理。

我在这里想念什么?我无法构建到 64 位,因为旧的 32 位库包含我们无法访问的专有算法,甚至梦想生产 64 位版本。我应该使用这些配置文件中的任何模式来准确识别这里失控的情况吗?

如果这个地址空间不能被清除,这是否意味着所有的 c# 应用程序最终都会因此而运行“内存不足”?

4

1 回答 1

3

几乎每一篇我曾经到过这一点的文章都表明内存不足实际上意味着连续的地址空间不足,并且考虑到正在使用的数量,我同意这一点。

这是一个合理的假设,但即使是合理的假设也可能是错误的。你的可能是错的。你该怎么办?

用科学测试它。也就是说,寻找证伪你的假设的证据。您想假设它是其他任何东西,并被您收集的证据所强迫,证明您的假设不是错误的。

所以:

  • 在您的应用程序内存不足时,它实际上是否没有必要大小的连续空闲页面?听起来您的观察确实表明这是正确的,因此该假设可能是错误的。

还有什么其他证据表明该假设可能是错误的?

  • “在有很多情节的作业中使用几个小时后,应用程序最终会耗尽内存。”
  • “使用 DevExpress,第三​​方控制供应商”
  • “错误对话框甚至无法在 MessageBox 中绘制错误图标”

这听起来不像是内存不足的问题。这听起来像是第三方控件库泄露了图形对象的操作系统句柄。不幸的是,此类泄漏通常表现为“内存不足”错误,而不是“句柄不足”错误。

所以,这是一个新的假设。 寻找支持和反对这一假设的证据。通过使用内存分析器,您做得很好。接下来使用句柄分析器

如果这个地址空间不能被清除,这是否意味着所有的 c# 应用程序最终都会因此而运行“内存不足”?

没有。GC 在清理托管内存方面做得很好;许多应用程序可以永远运行而不会泄漏。

于 2019-05-14T22:19:21.650 回答