代码之家  ›  专栏  ›  技术社区  ›  TheCloudlessSky

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

  •  16
  • TheCloudlessSky  · 技术社区  · 14 年前

    我有一个应用程序 许多 关于绘画,让我们假设它是一个类似Viso的应用程序。它具有具有多个子对象的对象,这些子对象可以绘制、连接、调整大小等。当前,当我在特定子对象或对象上调用“绘制”时,我会执行以下操作:

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

    我读过一些相互矛盾的答案,认为应该对一个不断绘制相同内容(可能只是调整大小、移动等)的应用程序这样做。我应该储存这些东西吗 Pen/Brush 然后在应用程序被释放时将它们全部释放,或者它们是否足够高效,可以为其创建/释放 每个 绘制调用(记住这是一个非常图形化的应用程序)。

    编辑

    5 回复  |  直到 14 年前
        1
  •  9
  •   Andy    14 年前

    当然,您可以使用Pens和brush类,这些类为您提供运行时已经创建的对象。

    Pens

    var pen = Pens.Red;
    

    同样的,你也可以用同样的方法 Brushes ,如果您只需要标准纯色笔刷颜色:

    var brush = Brushes.Red
    

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

    编辑:

    在我古老的XP机器上,以调试模式运行一个测试应用程序,创建和处理一个100000支新钢笔的数组大约需要半秒钟。

    相当于每支笔大约5微秒 . 只有你能决定这对你来说是否足够快。我冒昧地猜测,这一次对你们其余的行动来说可能是微不足道的。

        2
  •  3
  •   stevemegson    14 年前

    您只能通过在特定应用程序上进行测试来了解性能影响,但是在应用程序的生命周期中,框架似乎不存在保留几支笔的问题。你第一次打电话 Pens.Black ,它创建一支黑色钢笔并将其缓存。在以后的调用中,您会得到相同的对象,并且它从未显式地被释放(笔.黑.处理()将实际引发异常)。但是,您不希望盲目地创建笔并在应用程序结束时将其丢弃,因为这样会泄漏非托管内存。根据应用程序的使用模式,您会想到几个选项。

    为每个对象提供一支在设置前景色时创建的专用笔,并在所有绘画中重复使用。你应该使你的对象可以识别,这样它就可以正确地处理那支笔了。

    Dictionary<Color,Pen> 通过一个 PenCache.GetPen(ForeColor) . 喜欢用钢笔。黑色,您现在可以忘记处理它们。如果你只是简单地使用一种颜色,那么就不需要再使用了。这支笔被缓存了,所以你会永远记住它。你可以留一个 Dictionary<Color,WeakReference<Pen>> 相反,如果不再需要缓存的笔,允许它们最终被垃圾回收。

        3
  •  2
  •   Codesleuth    14 年前

    重复使用相同的 Pen Brush using .

    当你真正用完它们时,记得把它们处理掉。

        4
  •  0
  •   Grant Crofton    14 年前

    是的,最好像@fantius建议的那样进行测试,你可能会发现这其实并不重要——尽管我会临时保持它们打开,好像我正确地回忆起它们是非托管资源,可能会耗尽你的内存。如果每次都要重新创建它们,则需要特别小心地正确处理它们,以避免内存泄漏。

        5
  •  0
  •   Jamie    6 年前

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

    “我应该保持绘画资源,如钢笔和刷子,比什么是需要执行我的绘画操作的时间长”,问题是重新措辞?答案是不,你不应该在这种情况下;但是为什么,这是什么意思?

    当你绘制一个图形对象时,你正在为你创建的每个绘制对象使用内存密集型的资源,比如钢笔、画笔、路径、矩阵等等。

    是的,为绘画创作钢笔、画笔等myPen.dispose文件()并紧接着do释放对已释放对象的所有对象引用,方法是将该对象树设置为null,例如(myPen=null;),这允许垃圾收集器释放这些对象所持有的非托管内存,而不必等待对对象的调用完成()。请参见: Garbage collection

    “创建太多的这些IDisposable类对象,并且在完成时不释放这些对象” Using Stack and Heap 更多信息。

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

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

    注意:小心地将对象引用(如笔和画笔)传递给方法,如果这样做,则在类级别实现IDisposable接口以执行绘制。你的作业越来越贵了,建议你去看看 IDisposable interface .

    快乐画画!