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