使用应用程序在密集内存中进行 C# 垃圾收集
C# garbage collection in intense memory using application
我有一个图像编辑器程序。许多编辑器操作需要在内存中复制图像。图片可以很大,秒级编辑好几次,内存占用比较大。
我准确地 Dispose()
每个未使用的图像。但是当我分析我的应用程序时,我注意到在密集的编辑操作期间内存消耗增长(我什至 OutOfMemoryException
几次)。在几秒钟不活动后,它 returns 变为常规值,因此没有内存泄漏。所以我认为原因是垃圾收集发生的太少了。我在每次编辑操作后放置 GC.Collect()
,这很有帮助,现在内存消耗稳定了。
但是我想知道这是否是一个好方法?根据 MSDN:
It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.
我不需要收集应用程序中的所有内容,而只需销毁几个对象(Bitmap
's)。我能以某种方式告诉 GC 只收集这些对象吗?或者也许有另一种方法可以优化这个过程?
您可以为此过程使用 'using' 范围。
using(var bmp = new Bitmap(image))
{
/// your code
}
如果您可以在任何实现 IDispose 的东西上使用 'Using',那就去做吧。另一种选择是您的程序组织不当,无法管理流程,令人遗憾。
您应该始终让 Framework 在可能的情况下进行管理。
问自己的问题:
我是在创建对象的新实例而不是重复使用现有对象吗?
我可以在使用后将任何对象设置为空吗?或者完全处理掉它们?
哪条线路导致泄漏?我推荐 运行 该程序和
将 taskmanger 切换到一边 - 然后单步执行 - 你会看到斜坡
在您逐步完成时实时使用。
可以批量吗?如果我管理 100 张图片,我可以分成 10 组吗
共 10 个?
与垃圾收集器打交道总是一件棘手的事情,几乎在所有情况下都应该避免。
从性能的角度来看,最好的办法是通过重新使用对象和缓冲区来尽可能避免涉及 GC。这通常是以增加复杂性为代价的,如果可能的话,所以这是一种权衡。
否则,推荐的方法是设计您的应用程序以方便 GC:
- 确保在不再需要对象时尽早取消引用它们,以便可以快速收集它们。幸运的话,作为第 0 代或第 1 代。
- 在取消引用之前对实现它的对象调用 Dispose,以避免 GC 不得不保留对象来调用终结器。
由于我怀疑您已经这样做了,所以剩下的就是彻底的性能测试。如果你不经常释放一些大对象,因此 GC 很难预测,间隔,你可以证明你的应用程序执行得更好(不管那意味着什么)如果你调用 GC.Collect(),那么继续。
据我所知,您无法控制 GC 收集的内容。你甚至不能确定它会在调用 GC.Collect() 时收集你刚刚释放的大对象,如果它们已经进入 GC 第 1 代或第 2 代。这就是为什么你必须测试和测量你的特定用例.
一个问题是,GC 需要几秒钟才能赶上进度并且内存使用率会下降,这对您的应用程序是否真的很重要?
我有一个图像编辑器程序。许多编辑器操作需要在内存中复制图像。图片可以很大,秒级编辑好几次,内存占用比较大。
我准确地 Dispose()
每个未使用的图像。但是当我分析我的应用程序时,我注意到在密集的编辑操作期间内存消耗增长(我什至 OutOfMemoryException
几次)。在几秒钟不活动后,它 returns 变为常规值,因此没有内存泄漏。所以我认为原因是垃圾收集发生的太少了。我在每次编辑操作后放置 GC.Collect()
,这很有帮助,现在内存消耗稳定了。
但是我想知道这是否是一个好方法?根据 MSDN:
It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.
我不需要收集应用程序中的所有内容,而只需销毁几个对象(Bitmap
's)。我能以某种方式告诉 GC 只收集这些对象吗?或者也许有另一种方法可以优化这个过程?
您可以为此过程使用 'using' 范围。
using(var bmp = new Bitmap(image))
{
/// your code
}
如果您可以在任何实现 IDispose 的东西上使用 'Using',那就去做吧。另一种选择是您的程序组织不当,无法管理流程,令人遗憾。
您应该始终让 Framework 在可能的情况下进行管理。
问自己的问题:
我是在创建对象的新实例而不是重复使用现有对象吗?
我可以在使用后将任何对象设置为空吗?或者完全处理掉它们?
哪条线路导致泄漏?我推荐 运行 该程序和 将 taskmanger 切换到一边 - 然后单步执行 - 你会看到斜坡 在您逐步完成时实时使用。
可以批量吗?如果我管理 100 张图片,我可以分成 10 组吗 共 10 个?
与垃圾收集器打交道总是一件棘手的事情,几乎在所有情况下都应该避免。
从性能的角度来看,最好的办法是通过重新使用对象和缓冲区来尽可能避免涉及 GC。这通常是以增加复杂性为代价的,如果可能的话,所以这是一种权衡。
否则,推荐的方法是设计您的应用程序以方便 GC:
- 确保在不再需要对象时尽早取消引用它们,以便可以快速收集它们。幸运的话,作为第 0 代或第 1 代。
- 在取消引用之前对实现它的对象调用 Dispose,以避免 GC 不得不保留对象来调用终结器。
由于我怀疑您已经这样做了,所以剩下的就是彻底的性能测试。如果你不经常释放一些大对象,因此 GC 很难预测,间隔,你可以证明你的应用程序执行得更好(不管那意味着什么)如果你调用 GC.Collect(),那么继续。
据我所知,您无法控制 GC 收集的内容。你甚至不能确定它会在调用 GC.Collect() 时收集你刚刚释放的大对象,如果它们已经进入 GC 第 1 代或第 2 代。这就是为什么你必须测试和测量你的特定用例.
一个问题是,GC 需要几秒钟才能赶上进度并且内存使用率会下降,这对您的应用程序是否真的很重要?