Given a Font and a string, is there any ready-to-use function in .NET which can compute the resulting width of the string in pixels So that I can adapt say a Label, MenuItem or Textbox to the new size of a string.
I guess I'll have to plead ignorance on this. I come up with pretty much the same results as you when I try to find any leaked resources caused by not calling Dispose on Graphics objects.
I'm guessing that CreateGraphics is repeatedly handing out the same Graphics object and that's why the handle count doesn't grow. If that's the case, GetGraphics might be a better name.
You can varify that Dispose isn't called automatically, though. Here's what I did to test it. First, there's a very simple class that just implements IDisposable and writes to the console when it is disposed or finalized. The Shared function is there so I can get a reference to an instance without using a variable.Public Class TestDispose Implements IDisposable
Public Description As String
Private Sub New(ByVal description As String) Me.Description = description End Sub
Public Shared Function GetObject(ByVal description As String) As TestDispose Return New TestDispose(description) End Function
Public Sub Dispose() Implements System.IDisposable.Dispose Console.WriteLine("**{0} disposed**", Me.Description) GC.SuppressFinalize(Me) End Sub
Protected Overrides Sub Finalize() Console.WriteLine("**{0} finalized**", Me.Description) End Sub
End Class Then I created three buttons on a form and wrote the following: Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
TestDispose.GetObject("No dispose")
TestDispose.GetObject("Explicit dispose").Dispose() End Sub
Private Sub btnGCCollect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGCCollect.Click Console.WriteLine("Explicit garbage collection...") GC.Collect() End Sub
Private Sub btnCauseGCCollect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCauseGCCollect.Click Console.WriteLine("Inducing garbage collection...") For i As Integer = 0 To 100000 Dim o As New Object Next End Sub When btnGo is clicked, this is written to the console:**Explicit dispose disposed**The only cases "**No dispose finalized**" is written to the console are
1) btnGCCollect is clicked, which explicitly calls GC.Collect 2) btnCauseGCCollect is clicked, which creates a large number of objects, forcing a garbage collection 3) the application terminates.
At no time does **No dispose disposed** ever appear on the console. I guess it's possible that there are some special considerations for BCL objects like the Graphics class, but it's clear that dispose doesn't run unless explicitly called. This is one of those cases where it would be very helpful to have access to the source code to see how it works internally.
In any case, you're right that there doesn't seem to be any measureable difference between calling dispose on the Graphics object retrieved with CreateGraphics and not calling dispose at all.
So, it may have been all for naught, but at least it was interesting :)
Really Doesn't the Dispose method get called implicitly when you create an object without a variable to hold it I thought that was how the framework handled it...
I just added the following routine to a Button.Click event of an existing testing app:
For i As Integer = 1 To 100000 Label1.Width = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Width Label1.Height = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Height Label2.Text = i Application.DoEvents() Next
I started the app and windows task manager and watched the memory usage of the program. The app started with about 30,500K in use. I clicked the button once and ran that routine. The memory usage varied between 33,500K and 35,000K. When the routine stoped, the usage stabilized at about 33M. I could use various other controls on the form and the memory usage would climb and fall. I repeated this process two more times. In the end, the app was still consuming about 33M of memory.
So I didn't really see a sign of a memory leak... Are you sure the explicit call to Dispose is necessary
Well I usually always call .Dispose when a Graphics object is no longer needed.
In this case I have a Graphics object that lives as long as the program runs anyway (unless the window gets resized, then I create a new one, for I thought the old one could be no longer valid, since at least clip bounds have changed...)
Very interesting... I have to admit that I don't know much about the garbage collection process; but I just learned a good bit! Thanks :)
So the reason to call Dispose() is specifically for the sake of the garbage collector.
I guess the question then becomes, which is more efficient; coding to aid garbage collection or coding to aid execution speed (that is, reducing the number of lines of code).
I took your two examples and made one change; I USED the value returned by MeasureString():
Without doing a Console.WriteLine, the Dispose test takes about 1.85 seconds, while the No-Dispose test takes about 2.85 seconds. This is very consistant and quite a difference. But when you add the WriteLine statement, the times are within 1/100th of a second (~ 21 seconds each) with about an even split on which is the faster (sometimes Dispose, sometimes NoDispose).
When you also consider the fact that all of the tests in this thread are doing a minimum of 100,000 calls it seems unlikely that the overhead of the GC would negitivly impact the performace of the application given a reasonable number of calls.
I would have to say that if you are going to do thousands upon thousands of calls to IDisposable objects then you should probably Dispose() them for the GC's sake. But if you're only going to make those calls here and there, don't be affraid to code them inline.
I'll have to disagree. Many classes implement IDisposable because they hold onto unmanaged resources and the Dispose method is a standard way of telling the object to release those resources. Your example of choosing between aiding the garbage collector or aiding execution speed doesn't really hold up since aiding the garbage collector often increases execution speed. Speed is often not directly related to the number of lines of code.
Obviously, the large amount of calls to CreateGraphics in the examples was to illustrate the problem, but leaving one GDI handle or file handle dangling because dispose wasn't called on the object that held a reference to it is not good practice.
Unless you have specific knowledge that a class does not use the Dispose method to release unmanaged resources, you should always call dispose. The penalties for not doing so can range from performance degradation (from causing the garbage collector do more work) to IO exceptions because maybe you opened a file without disposing of the FileStream object that opened it.
My personal rule of thumb on this is simple: If a class implements IDisposable, trust that the developer of that class had a valid reason for it.
Now, I've never specifically heard it said that the CLR calls Dispose on objects without a variable; but to me, it just makes sense given the way inline code execution works. The object must be created in order for the line to execute, but since we haven't allocated any space to hold that object, it must be destroyed when the CLR is finished executing the line of code that created the object. If it didn't clean up after itself you wouldn't be able to do inline execution; every inline call would allocate resources that were never reclaimed (actually, it seems like there were some issues with this in Framework 1.0 using certain calls).
I just did a little research on this, and found the article "Resource Leaks: Detecting, Locating, and Repairing Your Leaky GDI Code" at http://msdn.microsoft.com/msdnmag/issues/01/03/leaks/default.aspx.
In this article, the author states the following:
"A good solution for detecting GDI leaks is to use dedicated tools such as the Purify or BoundsChecker tools I mentioned earlier. The main drawback of these tools is the same as the final MFC dump for memory leaks—you don't know about the leaks until the application ends. It would be nice to be able to take a snapshot of current GDI consumption, perform an action that might leak, and make a comparison with the current state. Under Windows 2000 you can use the Task Manager to do this kind of comparison, thanks to a new column that displays the count of GDI objects used by a process..."
I repeated the experiment in my previous post, this time looking at the GDI Objects column of the TaskManager. My application opened with 44 objects. When the button is clicked and the loop begins to execute, the GDI object count bounces around between 44 and 45, ocassionally hitting 46, and ending at 44 when the loop finishes. This confirms that the Graphics objects are implicitly disposed.
However, the fact that I can occasionally see the count hit 46 indicates that you are correct about it taking an extra run of garbage collection to reclaim the object. A value of 46 indicates that the first inline call to CreateGraphics was not completely disposed before the second call.
You gotta love this forum when it comes to learning more about .NET! Now I know how to look for GDI leaks in my apps; and it was a direct result of this discussion. =)
I didn't have a lot of time to plink with it today, but I did try a few other tests and could not cause an IO exception using inline reads of files, nor could I see a performance loss.
I have seen this function in the help long time ago, but I just couldn't remember the d^mn name & location and found nothing with google. But I knew it existed :-)
That's true, but bear in mind that the base System.Drawing.Graphics object doesn't expose this method. You need to get a Graphics object from the object you want to manipulate by calling its CreateGraphics method.
Here's an example of resizing a label based on it's own text and font:
Ok, you'll have to take my word that I haven't spent all day thinking about this :)
I wasn't planning to post on this thread again, but I happened to stop by <a href="http://msdn.microsoft.com">MSDN</a> and noticed a new <a href="http://msdn.microsoft.com/msdntv/episode.aspx xml=episodes/en/20050217CLRPS/manifest.xml">video</a> about the CLR Profiler. I've read about the tool before, but I'd never had a chance to use it. Anyway, I decided to see if it would help in figuring this out.
I still can't find any <i>direct</i> evidence of leaked GDI resources, which was my original point (the profiler doesn't track them), but the profiler provides plenty of evidence that not calling dispose causes lots of bad mojo. To test it, I wrote two versions of a console application. Here's the meat of both of them:// Version 1 - Dispose not called
Label label1 = new Label(); for(int i = 0; i < 100000; i++) { label1.CreateGraphics().MeasureString("Test", label1.Font); }
// Version 2 - Dispose called
Label label1 = new Label(); for(int i = 0; i < 100000; i++) { Graphics g = label1.CreateGraphics(); g.MeasureString("Test", label1.Font); g.Dispose(); }
The only functional difference between the two is that the first version does not dispose of the Graphics object obtained with CreateGraphics. By the way, I also had a version that used a separate variable for the Graphics object. It looked exactly like version 2 with the line g.Dispose() commented out. There was absolutely no difference between the results for it and Version 1.
Even before breaking out the CLR Profiler, I tested them for speed. The version that called Dispose excplicitly ran 12-14% faster than the non-dispose version. The reason is apparent once you run the profiler on the application. The version that calls dispose has every Graphics object reclaimed each time the garbage collector is run. In the version that doesn't call dispose, the Graphics objects survive until the application terminates!
On my machine there were four collections in all for the non-dispose version. Two generation 0, one generation 1, and one generation 2. Every single Graphics object survived them all. The only reason I can think of that an object with no references in code would survive even a generation 0 garbage collection is that is being kept alive another way, such as holding onto unmanaged resources.
Here's the reason for the difference in performance. Each time an object survives a garbage collection, it may be moved closer to the bottom of the managed heap. For the version that calls dispose, the garbage collector needed to move 3 instances of System.Drawing.Graphics, which account for 48 bytes and .02% of the GC's attention. For the non-dispose version, the GC moved 30,689 instances, which is 491,024 bytes and 76.75% of the total. That's a huge difference.
The moral of the story is to call Dispose on objects that implement IDisposable, especially ones that are known to hold onto unmanaged resources, such as GDI handles or database connections or file handles.
Well, it's not a memory leak you're worried about with Graphics objects. You're getting a handle to the DC that the Grashics object represents, so that's what is getting leaked.
I've never heard that the CLR calls Dispose on objects without a variable, not that I'm an expert on the inner workings of the .NET framework.
The resources will get reclaimed eventually, whether it's by calling Dispose explicitly or the CLR calling the finalizer. If the CLR calls the finalizer, though, it will take two runs of the garbage collector to actually reclaim the object because it first has to be placed in the finalization queue before it actually is destroyed.
It's probably one of those things that, in practice, you'll not notice any difference. I just try to make a habit of explicitly calling dispose on any object that implements IDisposable.
Like I said, you gotta love these forums for the brainstorming!
To clairify, the handle count DOES grow, it just shrinks again quickly. The number of GDI objects varied by 2 throughout the execution of the loop.
You're right, a view of the source code is the only way to get a real answer, but still, you're example makes me think that even though the actual method Dispose() is never called, the code that Dispose() executes may still be run...
The CLR may have a more generic teardown procedure so that it can execute the same code on IDisposable objects as those without the implementation. This is just speculation but it would make sense in that you could create a class that doesn't implement IDisposable, but still contains a method that returns an object. If you executed this method inline, the object created would still need a teardown. It would make sense for the CLR to have a teardown routine that can be run against any object, regardless of implementation.
This is definately a worthwhile discussion... if nothing else, it should ease minds about the use of inline coding. It has certainly reassured me! =)
That's also true, but bear in mind that you should always dipose of Graphics objects retrieved with CreateGraphics. Using CreateGraphics inline will leak resources. Dim gfx as Graphics = Label1.CreateGraphics() Dim labelSize as SizeF = gfx.MeasureString(Label1.Text, Label1.Font)
Calculate Width of a String in Pixels
ivj
I'm guessing that CreateGraphics is repeatedly handing out the same Graphics object and that's why the handle count doesn't grow. If that's the case, GetGraphics might be a better name.
You can varify that Dispose isn't called automatically, though. Here's what I did to test it. First, there's a very simple class that just implements IDisposable and writes to the console when it is disposed or finalized. The Shared function is there so I can get a reference to an instance without using a variable.Public Class TestDispose
Implements IDisposable
Public Description As String
Private Sub New(ByVal description As String)
Me.Description = description
End Sub
Public Shared Function GetObject(ByVal description As String) As TestDispose
Return New TestDispose(description)
End Function
Public Sub Dispose() Implements System.IDisposable.Dispose
Console.WriteLine("**{0} disposed**", Me.Description)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("**{0} finalized**", Me.Description)
End Sub
End Class
Then I created three buttons on a form and wrote the following:
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
TestDispose.GetObject("No dispose")
TestDispose.GetObject("Explicit dispose").Dispose()
End Sub
Private Sub btnGCCollect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGCCollect.Click
Console.WriteLine("Explicit garbage collection...")
GC.Collect()
End Sub
Private Sub btnCauseGCCollect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCauseGCCollect.Click
Console.WriteLine("Inducing garbage collection...")
For i As Integer = 0 To 100000
Dim o As New Object
Next
End Sub
When btnGo is clicked, this is written to the console:**Explicit dispose disposed**The only cases "**No dispose finalized**" is written to the console are
1) btnGCCollect is clicked, which explicitly calls GC.Collect
2) btnCauseGCCollect is clicked, which creates a large number of objects, forcing a garbage collection
3) the application terminates.
At no time does **No dispose disposed** ever appear on the console. I guess it's possible that there are some special considerations for BCL objects like the Graphics class, but it's clear that dispose doesn't run unless explicitly called. This is one of those cases where it would be very helpful to have access to the source code to see how it works internally.
In any case, you're right that there doesn't seem to be any measureable difference between calling dispose on the Graphics object retrieved with CreateGraphics and not calling dispose at all.
So, it may have been all for naught, but at least it was interesting :)
DecaysChampion
I just added the following routine to a Button.Click event of an existing testing app:
For i As Integer = 1 To 100000
Label1.Width = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Width
Label1.Height = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Height
Label2.Text = i
Application.DoEvents()
Next
I started the app and windows task manager and watched the memory usage of the program. The app started with about 30,500K in use. I clicked the button once and ran that routine. The memory usage varied between 33,500K and 35,000K. When the routine stoped, the usage stabilized at about 33M. I could use various other controls on the form and the memory usage would climb and fall. I repeated this process two more times. In the end, the app was still consuming about 33M of memory.
So I didn't really see a sign of a memory leak... Are you sure the explicit call to Dispose is necessary
newbieToVJS --Now C&#35;
In this case I have a Graphics object that lives as long as the program runs anyway (unless the window gets resized, then I create a new one, for I thought the old one could be no longer valid, since at least clip bounds have changed...)
rbedard
<a href="http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpref/html/frlrfSystemDrawingGraphicsClassMeasureStringTopic.asp">Graphics.MeasureString</a>
mettoffa
So the reason to call Dispose() is specifically for the sake of the garbage collector.
I guess the question then becomes, which is more efficient; coding to aid garbage collection or coding to aid execution speed (that is, reducing the number of lines of code).
I took your two examples and made one change; I USED the value returned by MeasureString():
Console.WriteLine(label1.CreateGraphics().MeasureString("Test", label1.Font).Width & " -" & i)
Without doing a Console.WriteLine, the Dispose test takes about 1.85 seconds, while the No-Dispose test takes about 2.85 seconds. This is very consistant and quite a difference. But when you add the WriteLine statement, the times are within 1/100th of a second (~ 21 seconds each) with about an even split on which is the faster (sometimes Dispose, sometimes NoDispose).
When you also consider the fact that all of the tests in this thread are doing a minimum of 100,000 calls it seems unlikely that the overhead of the GC would negitivly impact the performace of the application given a reasonable number of calls.
I would have to say that if you are going to do thousands upon thousands of calls to IDisposable objects then you should probably Dispose() them for the GC's sake. But if you're only going to make those calls here and there, don't be affraid to code them inline.
Asim
Obviously, the large amount of calls to CreateGraphics in the examples was to illustrate the problem, but leaving one GDI handle or file handle dangling because dispose wasn't called on the object that held a reference to it is not good practice.
Unless you have specific knowledge that a class does not use the Dispose method to release unmanaged resources, you should always call dispose. The penalties for not doing so can range from performance degradation (from causing the garbage collector do more work) to IO exceptions because maybe you opened a file without disposing of the FileStream object that opened it.
My personal rule of thumb on this is simple: If a class implements IDisposable, trust that the developer of that class had a valid reason for it.
Patrick Shirley
Now, I've never specifically heard it said that the CLR calls Dispose on objects without a variable; but to me, it just makes sense given the way inline code execution works. The object must be created in order for the line to execute, but since we haven't allocated any space to hold that object, it must be destroyed when the CLR is finished executing the line of code that created the object. If it didn't clean up after itself you wouldn't be able to do inline execution; every inline call would allocate resources that were never reclaimed (actually, it seems like there were some issues with this in Framework 1.0 using certain calls).
I just did a little research on this, and found the article "Resource Leaks: Detecting, Locating, and Repairing Your Leaky GDI Code" at http://msdn.microsoft.com/msdnmag/issues/01/03/leaks/default.aspx.
In this article, the author states the following:
"A good solution for detecting GDI leaks is to use dedicated tools such as the Purify or BoundsChecker tools I mentioned earlier. The main drawback of these tools is the same as the final MFC dump for memory leaks—you don't know about the leaks until the application ends.
It would be nice to be able to take a snapshot of current GDI consumption, perform an action that might leak, and make a comparison with the current state. Under Windows 2000 you can use the Task Manager to do this kind of comparison, thanks to a new column that displays the count of GDI objects used by a process..."
I repeated the experiment in my previous post, this time looking at the GDI Objects column of the TaskManager. My application opened with 44 objects. When the button is clicked and the loop begins to execute, the GDI object count bounces around between 44 and 45, ocassionally hitting 46, and ending at 44 when the loop finishes. This confirms that the Graphics objects are implicitly disposed.
However, the fact that I can occasionally see the count hit 46 indicates that you are correct about it taking an extra run of garbage collection to reclaim the object. A value of 46 indicates that the first inline call to CreateGraphics was not completely disposed before the second call.
You gotta love this forum when it comes to learning more about .NET! Now I know how to look for GDI leaks in my apps; and it was a direct result of this discussion. =)
Steve Stilwell
I didn't have a lot of time to plink with it today, but I did try a few other tests and could not cause an IO exception using inline reads of files, nor could I see a performance loss.
Shaneisasuper
I have seen this function in the help long time ago, but I just couldn't remember the d^mn name & location and found nothing with google. But I knew it existed :-)
jjm
Here's an example of resizing a label based on it's own text and font:
Label1.Width = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Width
Label1.Height = Label1.CreateGraphics.MeasureString(Label1.Text, Label1.Font).Height
ajteeder
I wasn't planning to post on this thread again, but I happened to stop by <a href="http://msdn.microsoft.com">MSDN</a> and noticed a new <a href="http://msdn.microsoft.com/msdntv/episode.aspx xml=episodes/en/20050217CLRPS/manifest.xml">video</a> about the CLR Profiler. I've read about the tool before, but I'd never had a chance to use it. Anyway, I decided to see if it would help in figuring this out.
I still can't find any <i>direct</i> evidence of leaked GDI resources, which was my original point (the profiler doesn't track them), but the profiler provides plenty of evidence that not calling dispose causes lots of bad mojo. To test it, I wrote two versions of a console application. Here's the meat of both of them:// Version 1 - Dispose not called
Label label1 = new Label();
for(int i = 0; i < 100000; i++)
{
label1.CreateGraphics().MeasureString("Test", label1.Font);
}
// Version 2 - Dispose called
Label label1 = new Label();
for(int i = 0; i < 100000; i++)
{
Graphics g = label1.CreateGraphics();
g.MeasureString("Test", label1.Font);
g.Dispose();
}
The only functional difference between the two is that the first version does not dispose of the Graphics object obtained with CreateGraphics. By the way, I also had a version that used a separate variable for the Graphics object. It looked exactly like version 2 with the line g.Dispose() commented out. There was absolutely no difference between the results for it and Version 1.
Even before breaking out the CLR Profiler, I tested them for speed. The version that called Dispose excplicitly ran 12-14% faster than the non-dispose version. The reason is apparent once you run the profiler on the application. The version that calls dispose has every Graphics object reclaimed each time the garbage collector is run. In the version that doesn't call dispose, the Graphics objects survive until the application terminates!
On my machine there were four collections in all for the non-dispose version. Two generation 0, one generation 1, and one generation 2. Every single Graphics object survived them all. The only reason I can think of that an object with no references in code would survive even a generation 0 garbage collection is that is being kept alive another way, such as holding onto unmanaged resources.
Here's the reason for the difference in performance. Each time an object survives a garbage collection, it may be moved closer to the bottom of the managed heap. For the version that calls dispose, the garbage collector needed to move 3 instances of System.Drawing.Graphics, which account for 48 bytes and .02% of the GC's attention. For the non-dispose version, the GC moved 30,689 instances, which is 491,024 bytes and 76.75% of the total. That's a huge difference.
The moral of the story is to call Dispose on objects that implement IDisposable, especially ones that are known to hold onto unmanaged resources, such as GDI handles or database connections or file handles.
Fahd
I've never heard that the CLR calls Dispose on objects without a variable, not that I'm an expert on the inner workings of the .NET framework.
The resources will get reclaimed eventually, whether it's by calling Dispose explicitly or the CLR calling the finalizer. If the CLR calls the finalizer, though, it will take two runs of the garbage collector to actually reclaim the object because it first has to be placed in the finalization queue before it actually is destroyed.
It's probably one of those things that, in practice, you'll not notice any difference. I just try to make a habit of explicitly calling dispose on any object that implements IDisposable.
AkoSam
To clairify, the handle count DOES grow, it just shrinks again quickly. The number of GDI objects varied by 2 throughout the execution of the loop.
You're right, a view of the source code is the only way to get a real answer, but still, you're example makes me think that even though the actual method Dispose() is never called, the code that Dispose() executes may still be run...
The CLR may have a more generic teardown procedure so that it can execute the same code on IDisposable objects as those without the implementation. This is just speculation but it would make sense in that you could create a class that doesn't implement IDisposable, but still contains a method that returns an object. If you executed this method inline, the object created would still need a teardown. It would make sense for the CLR to have a teardown routine that can be run against any object, regardless of implementation.
This is definately a worthwhile discussion... if nothing else, it should ease minds about the use of inline coding. It has certainly reassured me! =)
sarrafi
Dim gfx as Graphics = Label1.CreateGraphics()
Dim labelSize as SizeF = gfx.MeasureString(Label1.Text, Label1.Font)
Label1.Width = labelSize.Width
Label1.Height = labelSize.Height
<b>gfx.Dispose()</b>