我有一个应用程序可以执行 lot 绘图,让我们假装它是一个类似Viso的应用程序。它有一些对象有多个子对象被绘制,东西可以连接,调整大小等。目前,当我在特定的子对象或对象上调用paint时,我会执行以下操作:
using(var pen = new Pen(this.ForeColor))
{
// Paint for this object.
}
我已经阅读了相互矛盾的答案,应该为不断绘制相同内容的应用程序(可能仅调整大小,移动等)执行此操作。我应该将Pen/Brush
与对象一起存储,然后在处理应用程序时将它们全部丢弃,或者它们是否足够有效,可以为每个绘制调用创建/处理它们(记住这是一个漂亮的图形密集的应用程序)。
编辑:已经有两个答案存在冲突,这就是我不确定要进行切换的地方。有没有人对差异有任何统计数据?
答案 0 :(得分:9)
您当然可以使用Pens和Brushes类来为您提供已由运行时创建的对象。
例如,如果您想要一种标准颜色Pens,则可以执行以下操作:
var pen = Pens.Red;
同样,如果你只想要标准的实心画笔颜色,你可以对Brushes做同样的事情:
var brush = Brushes.Red
使用这些,您无需担心清理,处理或其他情况。
如果您想要自己创建不同的颜色,例如使用不同的alpha组件或渐变画笔,那么您仍然需要自己创建并适当地清理它们。
修改强>
要创建和处理一个由100,000个新笔组成的数组,在我古老的旧机器上花了大约半秒钟,在调试模式下运行测试应用程序。
相当于每支笔约5微秒 。只有你可以决定它是否足够快。我猜想这个时间对于你的其他行动来说可能是微不足道的。
答案 1 :(得分:3)
您只会通过测试特定应用程序来了解性能影响,但在应用程序的生命周期内保留一些笔似乎没有问题。第一次调用Pens.Black
时,它会创建一个黑色笔并对其进行缓存。对于将来的调用,您将获得相同的对象,并且它从未明确处理(Pens.Black.Dispose()实际上会抛出异常)。但是,您不希望盲目地创建笔并在应用程序结束时让它们被丢弃,因为您将泄漏非托管内存。根据应用程序的使用模式,可以想到几个选项。
为每个对象设置一个专用笔,该专用笔在设置ForeColor时创建并重复用于所有绘画。你应该使你的对象IDisposable,以便它可以正确处置该笔。
如果您使用相对较少的不同颜色,但许多对象使用每种颜色,您可能不希望每个对象都保留其自己的笔。创建一个保留Dictionary<Color,Pen>
的缓存类,并通过PenCache.GetPen(ForeColor)
将其移出。就像使用Pens.Black一样,你现在可以忘记处理它们了。如果您简单地使用颜色,然后再不需要它,则会出现问题。 Pen被缓存了,所以你永远坚持使用它。您可以保留Dictionary<Color,WeakReference<Pen>>
,允许缓存的笔最终被垃圾收集,如果不再需要它们。
最后一个选项可能是最好的通用解决方案,避免无偿创建和处理,同时让垃圾收集器确保孤立的笔不会造成太多的内存故障。当然,在您的特定情况下,它可能不会更好。
答案 2 :(得分:2)
在需要多次操作的操作中重复使用相同的Pen
和Brush
比使用using
每次处理它们要快得多。
我肯定会说尽可能多地重复使用这些(我以前见过代码比较,但我现在无法找到它们),但做时要记住当你真正完成它们时处理它们。
答案 3 :(得分:0)
最好像@fantius一样测试,你可能会发现它并不重要 - 虽然我很想让它们保持开放状态,好像我没记错它们是非托管资源并且可能耗尽你的记忆。如果你每次都在重新创建它们,你需要特别注意妥善处理它们以避免内存泄漏。
答案 4 :(得分:0)
好的,这是一个老问题,对某些人来说可能是新问题,并且有一个简单直观的解决方案,然后是详细解释。
“我是否应该坚持绘画资源,比如钢笔和画笔,比预制我的绘画操作所需的时间更长”,问题会被重新定义?答案是否定的,你不应该在这种情况下;但为什么,这是什么意思?
当您绘制到图形对象时,您正在为您创建的每个绘制对象使用内存密集型资源,无论是笔,画笔,路径,矩阵等等。
是的,创建笔,创建画笔等进行绘画并执行myPen.dispose()并立即执行以下操作:通过将该对象树设置为null(例如(myPen = null;)),释放对已处置对象的所有对象引用允许垃圾收集器释放这些对象持有的非托管内存,而不必等待对象finalize()的调用。有关垃圾收集如何在C#中工作的更多信息,请参阅:Garbage collection。
创建太多这些IDisposable类对象并且在完成“Using”时不释放这些对象它们会对程序的操作产生严重后果,例如导致可能的堆栈和堆内存异常,从而导致CPU使用率增加排除不必要数量的对象可能导致性能降低,甚至如果不加以检查就会导致运行时崩溃。有关详细信息,请参阅Stack and Heap。
故事的道德释放您不再需要的资源;如果你必须保留资源,那么当你“持有资源”希望避免负面后果时,可以测试对绩效的潜在影响。
经验法则:最重要的是,确保在退出“绘画事件”例程后释放所有资源。优选地,当您的每个绘制事件方法完成时,该方法隐式创建的任何资源也应如此完成。惩罚,任何对象引用*传递给那些方法,如笔和画笔等将被保持,直到调用基础对象finalize,这比必要的长,并且可以被认为是定义的一般术语中的内存泄漏。 *传递太多引用等于不可用内存的时间比预期或假设的时间长。
注意:小心地将对象引用(如笔和画笔)传递给方法,如果这样做,则在类级别实现IDisposable接口以执行绘制。你的作业变得更加昂贵,建议你查看IDisposable interface。
快乐的画!