[Gtk-sharp-list] Disposing problem

Gonšal Carrero Puig gcarrero@teklamedia.com
Tue, 11 Nov 2003 00:04:10 +0100


Jonathan, thanks for your great explanation. I think also have to do
some reading :D

I've also tried your solution:

  while(GLib.MainContext.Iteration()) {
                // do nothing
        }

After the dispose method, and now all is working fine. Again thanks a
lot!!!!

Gon├žal

On Mon, 2003-11-10 at 07:38, Bruno Fernandez-Ruiz wrote:
> Thanks a lot Jon for a clear explanation! I had been wondering for a
> long time about the finalization problem. You are right, in Java the
> finalization is not deterministic, but the collection is, and that's
> probably the main difference with the Bohem GC. I did not know about
> per-generation finalization in .NET, so I think I have some reading to
> do :)
> 
> Bruno
> 
> On Mon, 2003-11-10 at 01:31, Jonathan Pryor wrote:
> > There's the .NET/CIL interpretation, and then there's what Mono does.
> > 
> > For most of this, they actually agree. :-)
> > 
> > Unlike Java, .NET/CIL/Mono (eventually) will make an effort to run
> > object finalizers (Object.Finalize).  However, finalizers are run
> > specially: when a "dead" (unreferenced) object is found, the finalizer
> > isn't run immediately; instead, the object is placed on a finalization
> > queue, and during the NEXT GC the objects on the finalization queue are
> > executed.  Or, the objects in the finalization queue are run on a
> > separate thread.  Whatever.  Also note that the finalization queue is
> > per-generation, so if it's a Gen-2 object that was placed on the
> > finalization queue, it may not be until app-exit that the finalizer is
> > run.
> > 
> > Problem #1 is that everything that derives from GLib.Object has a
> > finalizer, and thus has the above deferred behavior with the GC system.
> > 
> > This, however, isn't the major problem.
> > 
> > The major problem is Problem #2 (as far as you're concerned), which is
> > that the gtk-sharp library is keeping a reference to all GLib objects. 
> > GLib.Object.PerformQueuedUnrefs is fully-managed code.
> > 
> > So, your understanding is correct, it's just that another library
> > (gtk-sharp) is keeping a reference to your objects (Pixbufs) without you
> > realizing it.  This is handled by the GLib.Object constructor & related
> > methods, so *every* GLib.Object-derived class will exhibit this
> > behavior.
> > 
> > To get gtk-sharp to remove it's reference to your objects, you need to
> > let it run GLib.Object.PerformQueuedUnrefs, which requires running the
> > idle handler.
> > 
> > Due to Problem #1, there will be a delay before the memory is generally
> > usable.  First you need to perform the queued unrefs, then the GC will
> > realize that the objects are unreachable, and (if GC.SuppressFinalize
> > hasn't been called on the object), the objects will be placed on the
> > finalization queue and collected on the NEXT GC (again, for that GC
> > generation).
> > 
> > Note that invoking Dispose() on the objects will call
> > GC.SuppressFinalize, so calling Dispose will remove the need to wait for
> > the 2nd GC to collect memory.
> > 
> > Where mono differs from the above is that the Boehem GC is used, and
> > things are still in flux, so it is less likely for finalizers to be
> > invoked.  This will likely change (if it hasn't been fixed already), as
> > we get a better GC infrastructure.
> > 
> >  - Jon
> > 
> > On Sun, 2003-11-09 at 13:57, Bruno Fernandez-Ruiz wrote:
> > > I understand from your message that under Gtk# managed objects are
> > > prevented to be GC'ed, and queued to be dereferenced in the unmanaged
> > > code. Your code should work as it allows idle cycles to happen
> > > (yielding). I will try it out on my Gtk# application and let you know if
> > > it works.
> > > 
> > > Now, I still have a question beyond Gtk#, and more related to the Mono
> > > runtime. 
> > > 
> > > Please accept my apologies if I am getting it wrong, but I assimilate
> > > the mono VM to a JVM, where both GUI and non GUI managed applications
> > > run on a managed memory heap. Roughly speaking, on a JVM, if after a
> > > marking cycle from the GC thread, there is not enough marked objects to
> > > be reclaimed to leave enough free memory for a requested allocation, the
> > > actual heap is expanded up. If the max heap is reached, and there is
> > > still more memory requested, then the application crashes with an out of
> > > memory error. 
> > > 
> > > In my sample using mono, I would expect the VM GC mark policy, whichever
> > > policy is used, to limit the amount of memory used, as the test objects
> > > are not kept referenced, at least by the application code. So either,
> > > the GC mark and sweep is not happening, or something else is keeping a
> > > reference to the objects that prevents finalization. Instead, CPU sky
> > > rockets, and the system starts swapping memory until freeze.
> > > 
> > > Could somebody please give me some light? My experience from heavily
> > > loaded server-side applications, enterprise level, ist that optimized GC
> > > is critical for system performance.
> > > 
> > > Thanks!
> > > Bruno
> > > 
> > > public class Test
> > > {
> > >         ~Test ()
> > >         {
> > >                 Console.WriteLine ("Finalized");
> > >         }
> > >                                                                                                                                                                                    
> > >         public static void Main ()
> > >         {
> > >                 for (long i = 10000000000; i > 0; i--)
> > >                         new Test ();
> > >         }
> > > }
> > > 
> > > 
> > > On Sun, 2003-11-09 at 18:32, Jonathan Pryor wrote:
> > > > The problem is that you're not a GUI app. :-)
> > > > 
> > > > PerformQueuedUnrefs is called from the Idle handler for the GUI.  The
> > > > Idle handler is run whenever the GUI is not busy.
> > > > 
> > > > (Recall that GUIs are event-driven, so if the user isn't doing anything,
> > > > and the app isn't doing anything, then the app is idle, so you can do
> > > > background work during idle processing.)
> > > > 
> > > > Your sample app doesn't have a GUI, so there's never an "idle time", so
> > > > the idle handler is never run, so PerfrmQueuedUnrefs is never called.
> > > > 
> > > > Some possible solutions:
> > > >   - Insert the code:
> > > > 	while(GLib.MainContext.Iteration()) {
> > > > 		// do nothing
> > > > 	}
> > > >     This should explicitly run the idle handler.  This should be run
> > > >     after the .Dispose() call.
> > > > 
> > > >   - Make Object.Dispose virtual, then make Pixbuf.Dispose free memory 
> > > >     immediately.
> > > > 
> > > >     This probably isn't a good idea, as GTK+ requires that all objects
> > > >     be disposed from the same thread, which is what PerformQueuedUnrefs
> > > >     does (since the idle handler is only run on the GUI thread, so only
> > > >     one thread will ever do the unrefs).
> > > > 
> > > >     Pixbuf might not have this requirement, though.  I have no idea.
> > > > 
> > > > The first option is the safest and simplest option, if it works.  Please
> > > > try it and let us know.
> > > > 
> > > >  - Jon
> > > > 
> > > > On Sat, 2003-11-08 at 13:55, Bruno Fernandez-Ruiz wrote:
> > > > > On Sat, 2003-11-08 at 20:54, Gon├žal Carrero Puig wrote:
> > > > > > Anyone knows why idle is never calling PerformedQueuedUnrefs?
> > > > > 
> > > > > I have seen similar problems in due to the GC thread never entering, and
> > > > > the heap expanding until memory exhaustion. Try to create many dummy
> > > > > objects that implement IDisposable, and see if they get reclaimed. When
> > > > > running the attached sample, I freeze the system and run out of memory.
> > > > > No collection ever happens. 
> > > > > 
> > > > > Is GC disabled by default in mono?
> > > > > 
> > > > > Bruno