c# GDI+,在循环中创建 LinearGradientBrush(内存泄漏)
今天我遇到了一个两难的境地。我创建了一个使用 GDI+ 在表单上绘图的应用程序。每秒由计时器触发绘图。 draw 方法使用 for 循环来迭代对象集合,如果它们处于某种状态,则绘制它们。
我想使用 LinearGradientBrush 来绘制它们,因为它看起来比简单的画笔好得多。看看下面的内容,
//minutes
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
b.Dispose();
}
我正在为循环的每次迭代创建一个新的 LinearGradientBrush(这让我很烦恼),但那是因为我必须这样做。我无法在循环外部创建一个,因为它的构造函数集要求我设置仅在循环内部已知的参数。
我发现在 LinearGradientBrush 对象上使用 dispose 方法并不是那么可靠。如果我运行我的应用程序并在任务管理器中查看它,它会喷出内存。当我添加 b = null 行时,它似乎有很大帮助,如下所示,
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
if (b != null)
{
b.Dispose();
b = null;
}
}
我只是想知道是否有更好的方法来使用 LinearGradientBrushes ?或者有更好的解决方案可以使用吗?
非常感谢
Today I came across a bit of a dilema. I have created an app that uses GDI+ to draw on a form. The drawing is triggered by a timer every second. The draw method uses a for loop to iterate through a collection of objects and if they are of a certain state, draw them.
I want to draw them using a LinearGradientBrush simply because it looks so much nicer than a simple Brush. Have a look at the following
//minutes
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
b.Dispose();
}
I am creating a new LinearGradientBrush for each iteration of the loop (which bothers me), but thats because I have to. I cannot create one outside the loop because its constructor set demands that I set parameters which are only ever known inside the loop.
I find that using the dispose method on the LinearGradientBrush object is not all that reliable. If I run my app and view it in Task manager, its spewing memory. When I then add the b = null line that seems to help hugely as follows
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
if (b != null)
{
b.Dispose();
b = null;
}
}
I am just wondering if there is a better way to work with LinearGradientBrushes ? Or is there a better solution to use ?
Many thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我建议使用“using”语句:
但是,请记住,Dispose() 不会释放(托管)内存。它只是释放非托管资源(这很重要,并且可能包括非托管内存)。在 GC 运行之前内存不会释放,这在循环期间可能不会发生。
但是,如果内存压力变得太高,垃圾收集器应该在循环内运行,并且您会看到它下降。这就是 .NET 的设计方式 - 只要接受它,不用担心。 GC 最终会回收这些内存,所以不用担心。
I would recommend using a "using" statement:
However, remember, Dispose() does not free (managed) memory. It just releases the unmanaged resources (which is important, and may include unmanaged memory). The memory will not free until the GC runs, which may not happen during your loop.
However, if the memory pressure gets too high, the garbage collector should run within your loop, and you'll see it drop. This is the way .NET is designed - just accept it, and don't worry. The GC will eventually collect this memory, so its not something to worry about.
为每个 LED 添加渐变画笔。将画笔存放起来,以便轻松取用。
如果您无法将其添加到该类中,那么您可以使用 Dictionary
这样,每个 Led 只需要一个画笔,而不是每个循环迭代一个画笔
(此外,在示例代码中,如果 !l.IsLit 则没有必要创建画笔)
Add a gradient brush to each Led.
If you can't add it to that class, then you could use a Dictionary<Led,GradientBrush> to store the brushes in to gain easy access to them.
That way you only need one brush per Led instead of one per loop iteration,
(Also, in your example code, there is no point creating the brush if !l.IsLit)
Dispose
与释放托管内存无关。这完全由 GC 处理,它“在需要时”运行。但是,由于刷子很可能带有手柄,因此您应该将其丢弃。我建议您在using
块中执行此操作,而不是手动调用Dispose
,因为这将确保即使存在以下情况也会调用Dispose
一个例外。Dispose
has nothing to do with freeing managed memory. That is handled entirely by GC, which runs "when needed". However, since the brush most likely holds a handle, you should dispose it. I would recommend that you do that in ausing
block instead of manually callingDispose
as this will make sureDispose
is called even in the presence of an exception.如果排列数量有限,您可能只需预先创建所有画笔一次:
第二个选项类似,但根据需要创建画笔;
其他答案是正确的,只要不损害任何东西,.NET 可能会允许托管内存使用量激增。但是,如果有许多 Led 对象需要循环,这应该有助于减少大量创建/删除操作。
If the number of permutations is limited you might just pre-create all your brushes once:
A second option is similar, but to create the brushes as needed;
The other answers are correct that .NET may allow managed memory usage to balloon as long as it's not harming anything. But this should help cut out a lot of the creating/deleting if there are many Led objects to loop through.