c# GDI+, Creating a LinearGradientBrush in a loop (memory leaks) - c#

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

I would recommend using a "using" statement:
foreach (Led l in MinuteGrid.Leds)
{
if (l.IsLit)
{
using(LinearGradientBrush b = new LinearGradientBrush(l.LedRectangle, Color.GreenYellow, Color.Green, 110))
{
g.FillRectangle(b, l.LedRectangle);
}
}
}
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.

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 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 a using block instead of manually calling Dispose as this will make sure Dispose is called even in the presence of an exception.

If the number of permutations is limited you might just pre-create all your brushes once:
LinearGradientBrush rectGreenBrush = new LinearGradientBrush(l.LedRect........);
LinearGradientBrush rectRedBrush = new LinearGradientBrush(l.LedRect........);
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = null;
if (xxx)
b = rectGreenBrush;
else if (yyyy)
b = rectRedBrush;
else.....
do painting
}
cleanup brushes
A second option is similar, but to create the brushes as needed;
List<LinearGradientBrush> createdBrushes = new List<LinearGradientBrush>();
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = null;
b = FindOrCreateBrushBasedOnLed(l, createdBrushes);
// if not already created, creates the brush and adds it to the list
do painting
}
foreach (LinearGradientBrush b in createdBrushes)
{
cleanup brushes
}
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.

Related

Windows Forms Parallel Drawing

Is it possible to draw on a panel using a Parallel.For loop? I have a multidimensional array of doubles, double[][] plants, and I want to draw the columns in parallel, where each entry in the array is drawn as a rectangle in a grid on the panel.
On the line with grapahics.FillRectangle(), I keep getting this error when I try:
An exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll but was not handled in user code
Additional information: Object is currently in use elsewhere.
Here is the code I am using:
Parallel.For(0, simWidth, i =>
{
Color plantColor;
RectangleF plantRectangle= new Rectangle();
SolidBrush plantBrush = new SolidBrush(Color.Black);
for (int j = 0; j < simHeight; ++j)
{
int r, g = 255, b;
r = b = (int)(255 * (Math.Tanh(simulation.plants[i, j]) + 1) / 2.0);
plantColor = Color.FromArgb(100, r, g, b);
plantBrush.Color = plantColor;
plantRectangle.Location = new PointF(i * cellSize, j * cellSize);
graphics.FillRectangle(plantBrush, plantRectangle);
}
plantBrush.Dispose();
});
I think what is happening is that the graphics object cannot handle multiple calls at once. Is there any way around this? I tried creating a local reference to the graphics object in each parallel call but that did not work.
Is it possible to draw on a panel using a Parallel.For loop?
No, not in any way that would actually be useful.
UI objects, such as a Panel, have "thread affinity". That is, they are owned by a particular thread, and must only ever be used in that thread.
GDI+ objects, like your Graphics object (you don't say where you got that object, but one hopes it was passed to you in PaintEventArgs…if not, you have other design flaws in your code) can be more forgiving, but are not thread-safe. You could add synchronization around the actual uses of the object, but those uses are the slow part. Serializing them will negate most of the benefit of concurrency in the code.
Your question does not make clear whether your use of Parallel here was even an actual attempt to address some specific performance problem, never mind what that problem actually was. There are numerous questions with answers on Stack Overflow that discuss various techniques for improving rendering performance in Windows Forms code.
In general, most of these techniques involve reducing the total amount of work done by caching as much as possible. Based on the code you've shown, there are at least two things you might want to do:
Cache the computations for the rectangles and colors. You can even do that part of the computation with Parallel, whenever the underlying parameters change.
Draw everything into a Bitmap object. This will have to be done single-threaded, but a) it doesn't have to be done in the UI thread that owns your UI objects, and b) you (again) can do this just once, whenever the underlying parameters change. Having drawn into a Bitmap, then you can just draw the Bitmap object when the Paint event occurs, instead of having to re-render everything from scratch.

Graphics, dispose before reuse?

I want to know, should i dispose a Graphic object before reusing it?
meaning i replace it´s value:
graphic = "createGraphic"
something like that, should i dispose before that?
here is an example code where i use it:
gmp.DrawImage(newImage, 0, 0);
if (newImage.Size != panelm.Size)
{
panelm.Invoke((MethodInvoker)delegate { panelm.Size = newImage.Size; });
this.Invoke((MethodInvoker)delegate { this.Size = newImage.Size; });
gmp.Dispose();
gmp = panelm.CreateGraphics();
};
So, this is in a while loop, before the while, i make gmp inherit panelm.
But, i never dispose of it in the loop, i just reuse it all the time, Except, if the sizes don´t match.
Then i need to recreate it (else it´s to big/small).
But now the thing is, should i dispose before, or should i just use creategraphic?
Also, the problem here is. I can´t use, "Using" on gmp. Cause if i do, i only have 2 possibilities.
1: create it before the while loop, and reuse it until the while loop ends ( meaning, i can never change it).
2: create it inside the while loop, (meaning it will be recreated every loop which i think will be a waste).
Thanks
So you're asking if you should call Dispose() on it before you give it a new value?
Graphics gmp = panelm.CreateGraphics();
//do work
gmp.Dispose();
gmp = panelm.CreateGraphics();
versus
Graphics gmp = panelm.CreateGraphics();
//do work
gmp = panelm.CreateGraphics();
As good practice, you should call Dispose() when you're done; although it will automatically get cleaned up by the garbage collector sometime if you don't, so you're not leaking resources either way.
Reference-type variables don't hold objects, but instead identify them; it may be helpful to think of them as object IDs. If a call to CreateGraphics returns "Object #4872", then it is necessary to ensure that something will call Dispose on Object #4872. If someVariable happens to hold "Object #4872", then saying someVariable.Dispose won't actually do anything to someVariable, but will instead call Dispose on object #4872. If the code were to overwrite the variable before calling Dispose, it would have no way of knowing which object needed to have its Dispose method called.

Image.RotateFlip leaking memory :/

Although I have been programming for about 11 years(mostly VB6, last 6 months C#), it's THE first time to actually ask a question :) I have found all my answers from teh interwebz but this issue i can't solve myself. Your site is among the most helpful places i have got the best answers from!
I will show the code i'm using (an extract of what's relevant). Problem is that when using RotateFlip method then the memory is increasing rapidly to ~200M and then get's collected by GC after some time. The main method calling it iterates about 30 times per second so the performance is of utmost importance here. I have tried using graphics matrix transform but this sometimes fails and shows non-flipped image. The application itself is based on using a webcam, hiding the preview, taking the callback picture and showing it in picturebox. It then overlays a rectangle on if from another class. That's the reason to use callback and not preview window.
Capture.cs class:
internal Bitmap LiveImage;
int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
{
LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer);
if (ExpImg) // local bool, used rarely when the picture saving is triggered
{
LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
LiveImage.PixelFormat);
using (a)
a.Save("ocr.bmp", ImageFormat.Bmp);
}
else // dmnit, rotateflip leaks like h*ll but matrix transform doesn't sometimes flip :S
{
LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
/*using (var g = Graphics.FromImage(LiveImage))
{
g.Transform = _mtx;
g.DrawImage(LiveImage, 0, 0);
}*/
}
GC.Collect(); // gotta use it with rotateflip, otherwise it gets crazy big, like ~200M :O
return 0;
}
}
In main form i have an event that's updating the picture in the picturebox:
private void SetPic()
{
pctCamera.Image = _cam.LiveImage;
_cam.PicIsFree = false;
}
Because i need to get the image to main form which is in another class then i figured the most logical is the exposed Bitmap which is updated on every callback frame.
The reason i don't want to use matrix transform is because it's slower and sometimes with this speed it fails to flip the image and the frequency of such behavior is quite different with different PC's with different hardware capabilities and CPU speeds, also the fastest framerate 30fps with a 1.2GHz CPU shows this very frequently.
So, can you help me to figure it out? I'm not actually using it in current version, i'm using the commented-out matrix transform because i feel bad for using GC.Collect :(
Thank You!!!
pctCamera.Image = _cam.LiveImage;
Heavy memory usage like you observe is a sure sign that you missed an opportunity to call Dispose() somewhere, letting the unmanaged resources (memory mostly) used by a bitmap get released early instead of letting the garbage collector do it. The quoted statement is one such case, you are not disposing the old image referenced by the picture box. Fix:
if (pctCamera.Image != null) pctCamera.Image.Dispose();
pctCamera.Image = _cam.LiveImage;
You can rewrite your code like this:
internal Bitmap LiveImage;
int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
{
using (LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer))
{
LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
if (ExpImg) // local bool, used rarely when the picture saving is triggered
{
var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
LiveImage.PixelFormat);
using (a)
a.Save("ocr.bmp", ImageFormat.Bmp);
}
}
return 0;
}
Bitmap is an Image class, and implements the IDispose. As you create Bitmap each time, I suggest to use using statement for automatically freeing the resources.
GC.Collect is there for this situation. Collecting the data is the ONLY way to free it and when creating HUGE bitmaps its the way to go. Does a GC.Collect really slow things down?
Other then that you should keep the number of bitmap copies as low as possible.

C# Static class member and System.Windows.Controls.Image performance issue

I am currently investigating a performance issue in an application and have highlighted the following;
I have a class -
public static class CommonIcons
{
...
public static readonly System.Windows.Media.ImageSource Attributes = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png");
...
}
As a test harness I then have the following code using this class to show the issue -
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = CommonIcons.Attributes,
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
At the start of the loop the time difference is less than 0.001 seconds, but after 20000 goes this has increased to 0.015 seconds.
If I don't use the static member and directly refer to my icon, then I do not have the performance hit, i.e.
for (int loop = 0; loop < 20000; loop++)
{
// store time before call
System.Windows.Controls.Image image = new System.Windows.Controls.Image
{
Source = typeof(CommonIcons).Assembly.GetImageFromResourcePath("Resources/attributes.png"),
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
SnapsToDevicePixels = true
};
// store time after call
// log time between before and after
}
But in my real world program I don't want to be creating the imagesource on every call (increased memory until a garbage collection), hence why a static member is used. However I also cannot live with the performance hit.
Can someone explain why the original code is creating this performance hit? And also a better solution for what I am trying to do?
Thanks
It smells like something to do with garbage collection. I wonder whether there's some kind of coupling between the ImageSource and the Image which is causing problems in your first case. Have you looked to see what the memory usage of your test harness looks like in each case?
Out of interest, what happens if you set the Source to null at the end of each iteration? I know this is a bit silly, but then that's a natural corollary of it being a test harness :) It might be a further indication that it's a link between the source and the image...
Can you store only constant strings like "Resources/attributes.png" in your CommonIcons class ?
The difference is not between static member or not, but it is that in the first version you create 20000 images all having the same imagesource. I don't know exactly what is going on, but under the hood there may be delegates created automatically which handle communication between imagesource and image and everytime if an event in the imagesource occurs, 20000 clients needs to be notified, so this is a large performance hit.
In the second version, each of the 20000 created images have their own imagesource so you don't experience this overhead.
Note that you should always dispose graphical objects like Images with their Dispose()-method after you are done with them, this will speed up your application a bit and lowers your general memory usage.

Disposing Brushes

I am having a few memory problems with a long running application; I have been inspecting the paint methods to insure that brushes are properly disposed. In the case where the Brush is created in the argument to the function, will the brush be disposed after the call?
The case is outlined below:
g.DrawString(valueText, Font, new SolidBrush(Color.Red),
I am not entirely certain, but I don't believe it is. This would be safer:
using(var redBrush = new SolidBrush(Color.Red)
{
g.DrawString(valueText, Font, redBrush);
}
No, you should do it manually. Do however examine the classes Brushes and SystemBrushes, for ready-made brushes that you can use without creating new ones (and that you also don't need to / should not dispose).

Categories

Resources