@KattMan said:
@spenk said:If an object only refers to managed resources then there is no need to manage the memory of objects that are scope to a single class or routine as their lifetime is tracked by the runtime and they are entirely the GC's responsibility
You obviously have never worked with object with a large unmanaged block of memory inside a loop where the object is constantly being re-used. In this case "Using" does not completly solve the problem. The situation is this, you have a bitmap variable inside a loop (Using or not) you process the image into another image (cant go with Using here) and save it and move to the next one. The .Net runtime sees the object constantly being reused so does not collect. But the unmanaged memory blocks are not always recovered and start fragmenting. Since the variables are constantly reused, the memory is not claimed and eventually you blow the memory stack and the app crashes. The only solution to this was to garuntee dispose set to nothing and GC.Collect. I no longer care what the theory is, I have seen this in practice.
Sounds like a Mono thing. It's actually known for its "conservative" GC -- that is, not collecting stuff that "looks like" it might be in use. It doesn't know for sure, though, cause the collector apparently doesn't know the difference between a pointer and an int.
Anyway...
(1) Variables aren't inside a loop. Code is inside a loop. At most the bitmap is being created in a loop, and I assume you mean over and over, since it's the only situation that makes sense without further info. In that case, the former bitmap gets replaced entirely, and is thus eligible for finalization. Finalizers for IDisposable's should be calling Dispose(), and if they aren't, that's a bug in the library.
(2) The runtime doesn't care whether an object is "used" or "reused". It cares whether that object is reachable. If running code has a reference to the object, even if you're not using it anymore, it can't be collected. This means it can be a good thing to set a reference variable to null once you're done with it, if you're not intending to immediately either leave the function or reuse the variable to refer to another object.
(3) GC.Collect() doesn't free unmanaged resources -- that's part of what "unmanaged" means, and it's the whole reason for the IDisposable interface.
(4) Non-"value type" objects aren't created on the stack in most
cases. (It's possible, if the JIT realizes the object will never be
used outside the current function, but should never be relied on.) And
any object in memory, if it's not on the stack and isn't "pinned", can
be (and often is) moved around to reduce fragmentation. Even "unmanaged" bitmaps and such are managed by the OS -- and
much better than you seem to be implying here. Only unmanaged memory can create such fragmentation problems. And if that's your problem, then TRWTF is that you're playing with P/Invoke and IntPtr's without knowing what you're doing, and then blaming the runtime for letting you.
(5) Two different bitmaps using the same memory is a WTF in itself, unless the OS does some copy-on-write thing i've never heard about.
In any case, if you have some code that can demonstrate this crash, i would *love* to see it. As would the .net team, no doubt. But til you can produce it, i call bullshit.
@KattMan said:
@spenk said:If you declare a variable and assign an instance of an object that requires Disposing (i.e. FileStream) and then call .Dispose and then assign a new instance you will not get any such error as you are not re-instantiating the object
Read up on the cause of System.ObjectDisposedException and think again.
Variables are not objects. They are *references* to objects. Reassigning has little to do with the old object, other than potentially making it unreachable (and thus, collectable). If the code below throws an exception on your VM, then your VM is broken.
[code]
Sub Main()
Dim b As System.Drawing.Bitmap
For i As Integer = Integer.MinValue To Integer.MaxValue
b = New System.Drawing.Bitmap(1024, 1024, Drawing.Imaging.PixelFormat.Format32bppArgb)
Console.WriteLine("{0} bytes left", GC.GetTotalMemory(False))
b.Dispose()
Next
End Sub
[/code]
This code has been running on my machine for 20 minutes now. And if you comment out the "b.Dispose()" line, you'll see why i called bullshit earlier. It still runs just fine, cause the finalizer for a Bitmap does what any self-respecting IDisposable's finalizer does -- it calls Dispose() on its own.