0

I have a simple code which seems to cause a memory leak for me:

Public Function NewAlphaBitmap(ByVal uWidth As Integer, ByVal uHeight As Integer) As Bitmap

    Return New Bitmap(uWidth, uHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

End Function

After a few loops of this...

Dim nBmp As Bitmap

For i As Integer = 0 To 1000
    nBmp = NewAlphaBitmap(5000, 5000)
Next

... I get an Out Of Memory error.

In my understanding, nBmp should automatically be disposed when I set it to a new Bitmap using NewAlphaBitmap, so there shouldn't be a memory leak.

But seemingly this isn't so.

What might be the problem here?

Edit:

The memory leak even persists when I do the following:

    For i As Integer = 0 To 1000
        nBmp = NewAlphaBitmap(5000, 5000)
        nBmp = Nothing
    Next
tmighty
  • 10,734
  • 21
  • 104
  • 218
  • No, a Bitmap needs to be explicitly disposed of. *Anything* which implements a `Dispose` method (and therefore is `IDisposable`) needs to be disposed of. – Ňɏssa Pøngjǣrdenlarp Dec 19 '17 at 01:31
  • Why didn't the MS guys make it so that it's automatically disposed when the object is set to nothing? – tmighty Dec 19 '17 at 01:42
  • I am sure I dont know. Maybe ping Eric Lippert and chew him out. (you aren't settings anything to Nothing anyway) – Ňɏssa Pøngjǣrdenlarp Dec 19 '17 at 01:46
  • @Plutonix When I say nBmp = nothing, the memory leak persists. Only when I call nBmp.Dispose, the memory leak goes away. Thanks, I will contact Eric. – tmighty Dec 19 '17 at 01:55
  • https://stackoverflow.com/q/5838608/1070452 – Ňɏssa Pøngjǣrdenlarp Dec 19 '17 at 01:56
  • Yes, thanks, but it's still not clear to me why they didn't include this one line in the wrapper to dispose the GDI+ object if it hasn't been destroyed. But perhaps they lay awake many nights thinking about if they should do it or not... (no joke). – tmighty Dec 19 '17 at 02:05
  • Requiring something to be Disposed makes it clear that you are done with it and it can be cleaned up. If it were otherwise, you could have things disappearing just because you havent used them in a long time. – Ňɏssa Pøngjǣrdenlarp Dec 19 '17 at 02:08
  • I wrote a wrapper around GDI+ myself when I used VB6, and I always got a last cry of death from the wrapper object. That's when I disposed the GDI+ object. I was thinking that it could still work this way, but I don't have any idea about GC and how the .NET wrapper is implemented. – tmighty Dec 19 '17 at 02:13
  • You don't set an object to `Nothing`. An object is something so how could it be `Nothing`? You set a variable to `Nothing`, i.e. you make it refer to no object. Why would you expect the object that that variable previously referred to to be disposed when that happens? What if that object is in use elsewhere? The .NET Framework does keep track of how many references there are to objects and an object that isn't referenced will be finalised by the garbage collector at some point but that point is indeterminate. You should learn about garbage collection. – jmcilhinney Dec 19 '17 at 02:24
  • You can figure out why setting a variable to nothing does not dispose the object. Give it some thought. – Eric Lippert Dec 19 '17 at 02:40
  • @EricLippert But why did you not include this simple line in the wrapper when the user destroys the wrapper object? Like this (pseudo-code): void LastCryOfDeath-> if m_hImage != 0 GidpDisposeImage(m_hImage) ? – tmighty Dec 19 '17 at 02:47
  • 1
    tbh I think if one is coming from VB6 COM reference counting, it is understandable that one would assume setting = Nothing would destroy the object. Of course, VB6 suffered from circular references and that paradigm _didn't work_, which is why .NET has GC and Dispose. – SSS Dec 19 '17 at 02:47
  • 2
    @tmighty, there is a _Finalize_ method which sort of does what you say, but you never know when it will be run. The convention is, if there a `Dispose` method, then you are expected to call it when you are finished with the object. If setting = Nothing destroyed the object, you would be unable to have more than one reference to the same object. Unless you had reference counting, which was tried - and failed - in VB6. – SSS Dec 19 '17 at 02:50
  • 2
    Ok suppose they did that. What if two variables referred to the object? Then what would happen if you used the valid reference in the remaining variable? Think it through. – Eric Lippert Dec 19 '17 at 02:51
  • I would let the user crash hard if he tried to reference an image object twice. :-D – tmighty Dec 19 '17 at 02:52
  • 1
    All right, so what happens when you pass a variable referring to a bitmap as an argument to a method? The argument is a variable, and the formal parameter gets a copy of the argument, so now we have two variables both referring to the same object. Would you like that to crash? – Eric Lippert Dec 19 '17 at 07:38
  • 1
    @tmighty If it's (semi-) automatic disposal you want, look at the `Using` block. This is the correct, exception-safe way to make sure that `Dispose` is called on an object that implements `IDisposable`. – Craig Dec 19 '17 at 16:10
  • @tmighty When you assign a new instance of a reference type to a variable, you just cut the pointer to the previous instance and the variable just point to the new instance while the previous instance is still in the memory. – Reza Aghaei Jan 08 '18 at 03:02

0 Answers0