我应该根据 Paint 请求创建新的笔/画笔还是在整个应用程序生命周期中保留它们?

发布于 2024-09-15 07:05:49 字数 457 浏览 5 评论 0 原文

我有一个可以进行大量绘图的应用程序,让我们假设它是一个类似 Viso 的应用程序。它的对象有多个被绘制的子对象,可以连接事物、调整大小等。目前,当我在特定的子对象或对象上调用 Paint 时,我会执行以下操作:

using(var pen = new Pen(this.ForeColor))
{
    // Paint for this object.
}

我读到了相互冲突的答案,这应该是为不断绘制相同内容(可能只是调整大小、移动等)的应用程序完成。我是否应该将 Pen/Brush 与对象一起存储,然后在处理应用程序时将它们全部处理掉,或者它们是否足够高效,可以为每个绘制调用创建/处理(请记住,这是一个非常图形密集型的应用程序)。

编辑:已经有两个答案存在冲突,这就是我不确定是否要进行切换的地方。有人有关于差异的统计数据吗?

I have an application that does a lot of drawing, let's pretend it's a Viso-like application. It has objects that have multiple sub-objects that are drawn, things can be connected, resized etc. Currently when I call paint on a particular sub-object or object, I do the following:

using(var pen = new Pen(this.ForeColor))
{
    // Paint for this object.
}

I've read conflicting answers that this should be done for an application that is constantly drawing the same thing (maybe just resized, moved etc). Should I store the Pen/Brush with the object and then dispose them all when the application is disposed of, or are they efficient enough to be created/disposed for each paint call (remembering that this is a pretty graphics intense application).

EDIT: There are already two answers that have conflicting answers and this is where I'm not sure to make the switch. Does anyone have any stats on the differences?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

謌踐踏愛綪 2024-09-22 07:05:49

您当然可以使用 Pens 和 Brushes 类,它们为您提供运行时已创建的对象。

例如,如果您想要一种标准颜色,您可以这样做:

var pen = Pens.Red;

同样,您可以使用 画笔执行相同操作,如果您只想要标准的纯色画笔颜色:

var brush = Brushes.Red

使用这些,您无需担心清理、处置或其他问题。

如果您想要自己创建不同的颜色,例如使用不同的 alpha 组件,或者渐变画笔,那么您仍然需要自己创建这些颜色并适当地清理它们。

编辑:

在我古老的 XP 机器上创建和处理 100,000 支新笔的数组大约需要半秒,并在调试模式下运行测试应用程序。

这相当于每笔大约 5 微秒。只有您可以决定这对您来说是否足够快。我大胆猜测,对于您的其余操作而言,这一次可能基本上无关紧要。

You could of course use the Pens and Brushes classes that provide you with objects that are already created by the runtime.

For example, if you want one of the standard colour Pens, you can do this:

var pen = Pens.Red;

Likewise you can do the same with Brushes, if you just want standard solid brush colours:

var brush = Brushes.Red

Using these, you don't need to worry about cleaning them up, disposing it or otherwise.

If you want different colours that you create yourself, for example with a different alpha component, or a gradient brush perhaps, then you still need to create these yourself and clean them up appropriately.

EDIT:

To create and dispose of an array of 100,000 new pens took approximately half a second on my ancient old XP machine, running a test app in Debug mode.

That equates to approximately 5 microseconds per pen. Only you can decide if that is fast enough for you. I would hazard a guess that this time may be largely insignificant with regard to the rest of your operations.

若能看破又如何 2024-09-22 07:05:49

您只能通过对特定应用程序进行测试来了解性能影响,但框架在应用程序的生命周期内保留几支笔似乎没有问题。第一次调用 Pens.Black 时,它会创建一支黑色笔并将其缓存。您可以为将来的调用返回相同的对象,并且它永远不会显式处置(Pens.Black.Dispose() 实际上会抛出异常)。但是,您不想盲目地创建笔并在应用程序结束时将其丢弃,因为您将泄漏非托管内存。根据应用程序的使用模式,我会想到几个选项。

为每个对象提供一支在设置前景色时创建的私有笔,并在所有绘画中重复使用。您应该将对象设置为 IDisposable,以便它可以正确处理该 Pen。

如果您使用相对较少的不同颜色,但许多对象使用每种颜色,您可能不希望每个对象都保留自己的笔。创建一些缓存类来保存Dictionary并通过PenCache.GetPen(ForeColor)将它们分发出去。就像使用 Pens.Black 一样,您现在可以忘记处理它们。如果您短暂使用一种颜色,然后不再需要它,就会出现问题。笔已被缓存,因此您将永远将其保留在内存中。您可以保留一个 Dictionary> 相反,允许缓存的笔在不再需要时最终被垃圾回收。

最后一个选项可能是最好的通用解决方案,避免无端创建和处置,同时让垃圾收集器确保孤立笔不会造成太多内存问题。当然,在您的具体情况下,它可能并没有更好。

You'll only know the performance impact by testing on your particular application, but the framework doesn't seem to have a problem keeping a few pens around for the life of the application. The first time you call Pens.Black, it creates a black pen and caches it. You get the same object back for future calls, and it's never explicitly disposed (Pens.Black.Dispose() will actually throw an exception). However, you don't want to blindly create pens and leave them to be disposed when the application ends, because you'll be leaking unmanaged memory. A couple of options spring to mind depending on the pattern of usage in your app.

Give each object a private Pen that's created when ForeColor is set and reused for all painting. You should make your object IDisposable so that it can dispose of that Pen properly.

If you're using relatively few distinct colours but lots of objects use each colour, you may not want each object to hold on to its own Pen. Create some cache class that keeps a Dictionary<Color,Pen> and hands them out through a PenCache.GetPen(ForeColor). Like using Pens.Black, you can now forget about disposing them. A problem arises if you use a colour briefly, then don't need it again. The Pen got cached, so you're stuck with it in memory forever. You could keep a Dictionary<Color,WeakReference<Pen>> instead, allowing cached pens to be eventually garbage collected if they're no longer needed.

That last option may be the best general purpose solution, avoiding gratuitous creation and disposal while letting the garbage collector make sure that orphaned pens don't cause too much memory trouble. It may, of course, not be any better in your particular case.

七七 2024-09-22 07:05:49

重复使用相同的画笔在多次需要它的操作中,比每次使用 using 处理它们要快得多。

我可以肯定地说,尽可能多地重用这些是一个好主意(我以前见过代码比较,但我现在无法获取它们),但是一定记得处理掉当你真正完成它们时。

Reusing the same Pen and Brush in operations that will require it many times over is going to be a lot faster than disposing of them each time with using.

I would say for sure that it's a good idea to reuse these as much as possible (and I've seen code comparisons before, but I can't source them right now) but do remember to dispose of them when you are truly finished with them.

羁绊已千年 2024-09-22 07:05:49

是的,最好像 @fantius 建议的那样进行测试,您可能会发现这并不重要 - 尽管我很想让它们保持打开状态,就好像我没记错一样,它们是非托管资源并且可能会耗尽您的内存。如果每次都重新创建它们,则需要特别小心正确处理它们以避免内存泄漏。

Yeah best to test like @fantius suggests, you'll probably find it doesn't really matter - although I'd be temped to keep them open as if I recall correctly they're unmanaged resources and could use up your memory. If you were recreating them every time, you'd need to be especially careful of disposing them properly to avoid memory leaks.

睡美人的小仙女 2024-09-22 07:05:49

好吧,这是一个老问题,对某些人来说可能是新问题,有一个简单直观的解决方案,后面有详细的解释。

“我是否应该持有比执行绘画操作所需的时间更长的绘画资源,例如钢笔和画笔”,问题被重新表述?答案是否定的,你不应该在这种情况下;但为什么,这意味着什么?

当您绘制图形对象时,您创建的每个绘制对象(无论是笔、画笔、路径、矩阵等)都会使用内存密集型资源。

是的,创建笔,创建画笔等用于绘画,并执行 myPen.dispose() ,然后立即通过将该对象树设置为 null 来释放对已处置对象的所有对象引用,例如 (myPen = null;) 这允许垃圾收集器可以释放这些对象所持有的非托管内存,而无需等待调用对象的finalize()。有关垃圾回收方式的详细信息,请参阅:垃圾回收在 C# 中工作。

创建太多此类 IDisposable 类对象,并且在完成后未释放这些对象“使用" 它们可能会对程序的运行产生严重后果,例如导致可能的堆栈和堆内存异常,通过对不必要数量的对象进行排序而导致 CPU 使用率增加,从而可能导致性能下降,甚至如果不加以控制,则会发生运行时崩溃。有关详细信息,请参阅堆栈和堆

故事寓意释放你不再需要的资源;如果您必须保留资源,请测试“保留资源”时对性能的潜在影响,希望避免负面后果。

经验法则:最起码,确保在退出“绘制事件”例程时释放所有资源。最好,当每个绘制事件方法完成时,该方法隐式创建的任何资源也应该完成。惩罚是,任何传递给钢笔和画笔等方法的对象引用将被保留,直到调用基础对象 Finalize 为止,这比必要的时间要长,并且在定义的一般术语中可以被视为内存泄漏。 *传递太多引用意味着内存无法使用的时间比预期或假设的时间更长。

注意:小心地将对象引用(如笔和画笔)传递给方法,如果这样做,请在类级别实现 IDisposable 接口来执行绘画。您的作业变得更加昂贵,建议您查看 IDisposable 接口

绘画快乐!

Okay this is an old question, it is probably new for some and has a simple and intuitive solution followed by a detailed explanation.

"Should I hold on to paint resources, like pens and brushes, longer than what is required to preform my painting operation", question is rephrased? The answer is no, you should not in that very context; but why, what does that mean?

When you are painting to a graphics object you are using memory intensive resources for each paint object you create, be it a pen, brush, path, matrix and so on.

Yes, do create pens, create brushes etc. for painting and do myPen.dispose() and immediately following do release all object references to the disposed object by setting that object tree to null such as (myPen = null;) this allows the garbage collector to release unmanaged memory held by these objects without having to wait for the call to object finalize(). See: Garbage collection for more information about how garbage collection works in C#.

Creating too many of these IDisposable class objects and not releasing these objects when finished "Using" them can have serious consequences to your program's operation such as causing possible stack and heap memory exceptions, causing increased CPU usage by having to sort through unnecessary quantities of objects potentially causing slow performance and even a runtime crash if left unchecked. See about the Stack and Heap for more information.

Moral of the story release resources you no longer require; if you must retain resources, bench test the potential effects on performance when you "hold on to resources" hopefully avoiding negative consequences.

Rule of thumb: At the out most, ensure all resources are released upon exiting your "paint event" routine. Preferably, When each of your paint event methods finish so too should any resources implicitly created by that method. Penalty, any object references *passed to those methods like pens and brushes etc. will be held until base object finalize is called which is longer than necessary and can be considered a memory leak in the general terms of the definition. *Pass too many references equals unusable memory for a longer period than what probably is expected or assumed.

Note: Cautiously pass object references like pens and brushes to methods and if doing so implement an IDisposable interface at a class level to perform your painting. Your homework just got more expensive and recommend checking out the IDisposable interface.

Happy painting!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文