After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 580520 - Revert "Unparent rather than destroy MutterWindows."
Revert "Unparent rather than destroy MutterWindows."
Status: RESOLVED FIXED
Product: mutter
Classification: Core
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: mutter-maint
mutter-maint
Depends on:
Blocks:
 
 
Reported: 2009-04-27 22:54 UTC by Owen Taylor
Modified: 2009-06-23 18:16 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Revert "Unparent rather than destroy MutterWindows." (2.46 KB, patch)
2009-04-27 22:54 UTC, Owen Taylor
none Details | Review

Description Owen Taylor 2009-04-27 22:54:22 UTC
The commit:

commit 16d49695ad07555a36fe7ad4f60067fc944689f4
Author: Tomas Frydrych <tf@linux.intel.com>
Date:   Mon Feb 9 16:39:26 2009 +0000

    Unparent rather than destroy MutterWindows.

      clutter_actor_destroy() is pure evil, wreaking havoc in
      reference tracking.

Causes quite a bit of a problem for gnome-shell; because the actor is
only removed, if a Javascript reference was ever created for it, the
actor and it's textures stick around until that Javascript object
is garbage collected. Since it's a small Javascript object pointing
to a big texture, the GC system in spidermonkey doesn't see memory
pressure, and collection doesn't happen in a timely fashion.

Calling destroy() won't result in the actor being collected any faster,
but since the textures are freed, the memory impact is much, much less
and not problematical.

Using destroy() when you know an actor is going away is always right,
it also avoids problems with cyclic reference counts, which are very
easy to get in the combination of signal connections and language
bindings.

The reference count behavior of destroy() is very well defined - it's
just exactly the same as unparent(), so it's not clear to me what the
commit message refers to. Obviously there was some real problem being
fixed, but I think this wasn't the right fix. I'd be happy to provide
alternate ideas given details.
Comment 1 Owen Taylor 2009-04-27 22:54:29 UTC
Created attachment 133460 [details] [review]
Revert "Unparent rather than destroy MutterWindows."

This reverts commit 16d49695ad07555a36fe7ad4f60067fc944689f4.

If we want an actor to go away deterministically, we should call
clutter_actor_destroy(); using unparent instead a) may result
leaks through cyclic ref counts, and b) will delay the deallocation
of the window texture in a garbage collected environment until
the next garbage collection, causing much greater transient use
of memory.
Comment 2 Tomas Frydrych 2009-04-28 06:17:49 UTC
This change was put in place because using clutter_actor_destroy() is generally bad practice, unparenting is the normal way to dispose of actors. Using destroy() means you cannot manage actor life span by simply taking a reference to it, and is particularly problem if it takes place inside signal emission, where it pretty much invariably causes crashes.

Having said that, the last scenario is not likely with the MutterWindow, so reverting this might be possible, but I need to test it extensively first.
Comment 3 Owen Taylor 2009-04-28 12:43:10 UTC
If destroy inside signal emission invariably causes crashes, then that would reflect (serious) bugs in Clutter. We did a lot of work in the early days of GTK+ to make the object/signal system absolutely robust against that, and that work was carried over into the design of GObject.

It's worth keeping in mind that destroy() does not immediately cause an object to be freed, but rather it "breaks links" - the object releases references to other objects and other objects are requested to drop references to that object. That will frequently cause the refcount to go to zero and the object to be freed, but explicit reference counts (like the one held by the signal system while emitting a signal on the object) are unaffected.

Consider the following code:

  parent = Clutter.Group();
  child = Clutter.Text({ reactive: true, text: "Hello" });
  parent.add_actor('child');
  child.connect('button-press-event', function() {
     parent.x = parent.y = 50;
  })
  
  grandparent.add_actor(parent);

If we try to get rid of that combination of actors by doing:

  grandparent.remove_actor(parent);

Then we are left with a reference cycle:

  
          parent => child => javascript closure 
            \...........<=.........../

This cycle cannot be collected because it includes both the Javascript garbage collection system and C reference counting. (The problem is general to basically all combinations of C and another language: it's not Javascript specific.)

On the other hand, if you simply do parent.destroy(), then the parent will be removed from the grandparent, the child destroyed recursively, signal connections on the child disconnected, and everything properly freed.
Comment 4 Tomas Frydrych 2009-04-29 08:50:47 UTC
I understand your problem, but my concern is that once the actor is disposed of, there is not much you can do with it, even it if is not finalized, and in the past using clutter_actor_destroy() gave me nothing but grief -- anyway, I am going to apply locally and test for a while.
Comment 5 Owen Taylor 2009-06-19 19:48:21 UTC
Ping on this?
Comment 6 Tomas Frydrych 2009-06-22 07:52:59 UTC
Let's do this; if the old problems resurface, we will need to find a better way of fixing them.
Comment 7 Owen Taylor 2009-06-23 18:16:18 UTC
Pushed