Merge lp:~unity-team/unity/plugging-leaks-with-a-nailgun into lp:unity

Proposed by Mikkel Kamstrup Erlandsen
Status: Merged
Merged at revision: 566
Proposed branch: lp:~unity-team/unity/plugging-leaks-with-a-nailgun
Merge into: lp:unity
Diff against target: 550 lines (+194/-92)
6 files modified
unity-private/places/places-button.vala (+8/-4)
unity-private/places/places-default-renderer-group.vala (+126/-54)
unity-private/places/places-default-renderer.vala (+12/-1)
unity-private/places/places-view.vala (+24/-16)
unity/unity-layered-bin.vala (+17/-12)
unity/unity-stripe-texture.vala (+7/-5)
To merge this branch: bzr merge lp:~unity-team/unity/plugging-leaks-with-a-nailgun
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Approve
Review via email: mp+37231@code.launchpad.net

Description of the change

This branch plugs some leaks we could have in places. These leaks where normally only exposed after several minutes of exercising the places (especially visible on low end graphics hardware like my i945).

While the virt mem can still spike up to dangerous levels causing massive slowdowns it seems that it's eventually garbage collected by the driver and the mem usage goes down to a (somewhat) sane level.

To post a comment you must log in.
Revision history for this message
Neil J. Patel (njpatel) wrote :

Went through and checked all the nooks & crannies of places and they all seem to work fine. It definitely feels faster and mem usage seems reasonable on my system even after a bunch of place switches.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'unity-private/places/places-button.vala'
--- unity-private/places/places-button.vala 2010-09-17 15:19:02 +0000
+++ unity-private/places/places-button.vala 2010-10-01 09:55:56 +0000
@@ -95,11 +95,14 @@
95 if (glow is Ctk.EffectGlow)95 if (glow is Ctk.EffectGlow)
96 glow.set_invalidate_effect_cache (true);96 glow.set_invalidate_effect_cache (true);
97 });97 });
9898
99 /* Must not point to a lambda or non-static method on 'this'.
100 * Causes self-refs, hence leaks, otherwise */
99 outline_func = rounded_rect;101 outline_func = rounded_rect;
100 }102 }
101103
102 public void rounded_rect (Cairo.Context cr, int width, int height)104 /* This method *must* be static. Otherwise we'll create a circular ref to self */
105 private static void rounded_rect (Cairo.Context cr, int width, int height)
103 {106 {
104 var padding = 1;107 var padding = 1;
105 var x = padding;108 var x = padding;
@@ -125,7 +128,8 @@
125 cr.curve_to (x, height,128 cr.curve_to (x, height,
126 x, height,129 x, height,
127 x, height - radius);130 x, height - radius);
128 cr.close_path (); }131 cr.close_path ();
132 }
129133
130 private void paint_bg (Cairo.Context cr, int width, int height)134 private void paint_bg (Cairo.Context cr, int width, int height)
131 requires (this is Button)135 requires (this is Button)
132136
=== modified file 'unity-private/places/places-default-renderer-group.vala'
--- unity-private/places/places-default-renderer-group.vala 2010-09-22 18:20:59 +0000
+++ unity-private/places/places-default-renderer-group.vala 2010-10-01 09:55:56 +0000
@@ -59,7 +59,10 @@
59 private Ctk.Image icon;59 private Ctk.Image icon;
60 private Ctk.Text text;60 private Ctk.Text text;
61 private Expander expander;61 private Expander expander;
62 private unowned Ctk.IconView renderer;62
63 /* If renderer is null it indicates that we have been disposed,
64 * and that all changes to the results should be ignored */
65 private unowned Ctk.IconView? renderer;
6366
64 private MoreResultsButton? more_results_button;67 private MoreResultsButton? more_results_button;
6568
@@ -73,8 +76,17 @@
7376
74 public signal void activated (string uri, string mimetype);77 public signal void activated (string uri, string mimetype);
75 78
76 private GLib.List<Tile?> cleanup_tiles = new GLib.List<Tile?> ();79 private Gee.Queue<Tile> cleanup_tiles = new Gee.LinkedList<Tile> ();
77 private uint cleanup_operation = 0;80 private uint cleanup_operation = 0;
81
82 private TileFactory tile_factory;
83
84 private delegate Tile TileFactory (Dee.ModelIter iter,
85 string uri,
86 string icon_hint,
87 string mimetype,
88 string display_name,
89 string comment);
7890
79 public DefaultRendererGroup (uint group_id,91 public DefaultRendererGroup (uint group_id,
80 string group_renderer,92 string group_renderer,
@@ -86,7 +98,7 @@
86 group_renderer:group_renderer,98 group_renderer:group_renderer,
87 display_name:display_name,99 display_name:display_name,
88 icon_hint:icon_hint,100 icon_hint:icon_hint,
89 results:results);101 results:results);
90 }102 }
91103
92 construct104 construct
@@ -98,6 +110,22 @@
98 allow_expand = false;110 allow_expand = false;
99 else if (group_renderer == "UnityFolderGroupRenderer")111 else if (group_renderer == "UnityFolderGroupRenderer")
100 bin_state = ExpandingBinState.EXPANDED;112 bin_state = ExpandingBinState.EXPANDED;
113
114 /* Find the right tile factory for our rendering mode
115 * IMPORANT: The file_factory must *not* point to a lambda or
116 * non-static method on 'this'. That leads to self-refs (aka leaks) */
117 if (group_renderer == "UnityFileInfoRenderer")
118 {
119 tile_factory = file_info_tile_factory;
120 }
121 else if (group_renderer == "UnityShowcaseRenderer")
122 {
123 tile_factory = showcase_tile_factory;
124 }
125 else
126 {
127 tile_factory = default_tile_factory;
128 }
101129
102 vbox = new Ctk.VBox (SPACING);130 vbox = new Ctk.VBox (SPACING);
103 vbox.spacing = SPACING;131 vbox.spacing = SPACING;
@@ -240,6 +268,28 @@
240 results.row_removed.connect (on_result_removed);268 results.row_removed.connect (on_result_removed);
241269
242 }270 }
271
272 private override void dispose ()
273 {
274 if (renderer != null)
275 {
276 /* Drop refs to renderer since we have a cycle:
277 * self->renderer vs self->vbox->renderer */
278 renderer = null;
279 remove_actor (vbox);
280
281 /* Disconnect signals, so we don't start doing funky stuff
282 * after we've been disposed */
283 results.row_added.disconnect (on_result_added);
284 results.row_removed.disconnect (on_result_removed);
285
286 /* Drain the cleanup queue */
287 cleanup_tiles.clear ();
288 }
289
290 /* Chain up */
291 base.dispose ();
292 }
243293
244 private override void allocate (Clutter.ActorBox box,294 private override void allocate (Clutter.ActorBox box,
245 Clutter.AllocationFlags flags)295 Clutter.AllocationFlags flags)
@@ -264,68 +314,76 @@
264 /*314 /*
265 * Private Methods315 * Private Methods
266 */316 */
317
318 /* This method *must* be static in order to avoid self refs */
319 private static Tile file_info_tile_factory (Dee.ModelIter iter,
320 string uri,
321 string icon_hint,
322 string mimetype,
323 string display_name,
324 string comment)
325 {
326 return new FileInfoTile (iter, uri, icon_hint, mimetype, display_name, comment);
327 }
328
329 /* This method *must* be static in order to avoid self refs */
330 private static Tile showcase_tile_factory (Dee.ModelIter iter,
331 string uri,
332 string icon_hint,
333 string mimetype,
334 string display_name,
335 string comment)
336 {
337 return new ShowcaseTile (iter, uri, icon_hint, mimetype, display_name, comment);
338 }
339
340 /* This method *must* be static in order to avoid self refs */
341 private static Tile default_tile_factory (Dee.ModelIter iter,
342 string uri,
343 string icon_hint,
344 string mimetype,
345 string display_name,
346 string comment)
347 {
348 return new DefaultTile (iter, uri, icon_hint, mimetype, display_name, comment);
349 }
350
267 private void on_result_added (Dee.ModelIter iter)351 private void on_result_added (Dee.ModelIter iter)
268 {352 {
353 /* Ignore result set changes if we are disposed */
354 if (renderer == null)
355 return;
356
269 if (!interesting (iter))357 if (!interesting (iter))
270 return;358 return;
271359
272 if (n_results == OMG_FOOTEL_SUCKS_CANT_HANDLE_MANY_TEXTURES)360 if (n_results == OMG_FOOTEL_SUCKS_CANT_HANDLE_MANY_TEXTURES)
273 return;361 return;
274 362
275 Tile button;363 /* Try to reuse a tile from the cleanup queue. We are guaranteed
276 364 * that it's the right type because all tiles are created from the same
277 if (cleanup_tiles.length () > 0)365 * tile_factory instance */
366 Tile? button = cleanup_tiles.poll ();
367
368 if (button is Tile)
278 {369 {
279 button = cleanup_tiles.nth_data (0);
280 button.update_details (results.get_string (iter, 0),370 button.update_details (results.get_string (iter, 0),
281 results.get_string (iter, 1),371 results.get_string (iter, 1),
282 results.get_string (iter, 3),372 results.get_string (iter, 3),
283 results.get_string (iter, 4),373 results.get_string (iter, 4),
284 results.get_string (iter, 5));374 results.get_string (iter, 5));
285 button.iter = iter;375 button.iter = iter;
286 cleanup_tiles.remove (button);
287 button.unref (); /* Because Vala holds references when it shouldn't*/;
288 }
289 else if (group_renderer == "UnityFileInfoRenderer")
290 {
291 button = new FileInfoTile (iter,
292 results.get_string (iter, 0),
293 results.get_string (iter, 1),
294 results.get_string (iter, 3),
295 results.get_string (iter, 4),
296 results.get_string (iter, 5));
297
298 renderer.add_actor (button);
299 button.show ();
300 button.unref (); /* Because Vala holds references when it shouldn't*/;
301 button.activated.connect ((u, m) => { activated (u, m); });
302 }
303 else if (group_renderer == "UnityShowcaseRenderer")
304 {
305 button = new ShowcaseTile (iter,
306 results.get_string (iter, 0),
307 results.get_string (iter, 1),
308 results.get_string (iter, 3),
309 results.get_string (iter, 4),
310 results.get_string (iter, 5));
311 renderer.add_actor (button);
312 button.show ();
313 button.unref (); /* Because Vala holds references when it shouldn't*/;
314
315 button.activated.connect ((u, m) => { activated (u, m); });
316 }376 }
317 else377 else
318 {378 {
319 button = new DefaultTile (iter,379 button = tile_factory (iter,
320 results.get_string (iter, 0),380 results.get_string (iter, 0),
321 results.get_string (iter, 1),381 results.get_string (iter, 1),
322 results.get_string (iter, 3),382 results.get_string (iter, 3),
323 results.get_string (iter, 4),383 results.get_string (iter, 4),
324 results.get_string (iter, 5));384 results.get_string (iter, 5));
325 renderer.add_actor (button);385 renderer.add_actor (button);
326 button.show ();386 button.show ();
327 button.unref (); /* Because Vala holds references when it shouldn't*/;
328
329 button.activated.connect ((u, m) => { activated (u, m); });387 button.activated.connect ((u, m) => { activated (u, m); });
330 }388 }
331389
@@ -350,21 +408,27 @@
350408
351 private bool cleanup_operation_callback ()409 private bool cleanup_operation_callback ()
352 {410 {
353 foreach (Tile? tile in cleanup_tiles)411 Tile? tile;
412
413 /* Drain the cleanup queue */
414 while ((tile = cleanup_tiles.poll ()) != null)
354 {415 {
355 renderer.remove_actor (tile);416 /* If we are disposed renderer will be null */
417 if (renderer == null)
418 renderer.remove_actor (tile);
356 }419 }
357420
358 cleanup_tiles = null;
359 cleanup_tiles = new GLib.List<Tile?> ();
360
361 cleanup_operation = 0;421 cleanup_operation = 0;
362 return false;422 return false;
363 }423 }
364424
365 private void on_result_removed (Dee.ModelIter iter)425 private void on_result_removed (Dee.ModelIter iter)
366 {426 {
367 if (!interesting (iter))427 /* Ignore result set changes if we are disposed */
428 if (renderer == null)
429 return;
430
431 if (!interesting (iter))
368 return;432 return;
369433
370 var children = renderer.get_children ();434 var children = renderer.get_children ();
@@ -374,7 +438,7 @@
374438
375 if (tile.iter == iter)439 if (tile.iter == iter)
376 {440 {
377 cleanup_tiles.append (tile);441 cleanup_tiles.offer (tile);
378 if (cleanup_operation == 0)442 if (cleanup_operation == 0)
379 cleanup_operation = Timeout.add (200, cleanup_operation_callback);443 cleanup_operation = Timeout.add (200, cleanup_operation_callback);
380444
@@ -402,6 +466,10 @@
402466
403 private void add_to_n_results (int i)467 private void add_to_n_results (int i)
404 {468 {
469 /* Ignore result set changes if we are disposed */
470 if (renderer == null)
471 return;
472
405 n_results += i;473 n_results += i;
406474
407 if (n_results > renderer.get_n_cols ())475 if (n_results > renderer.get_n_cols ())
@@ -430,6 +498,10 @@
430498
431 private void on_n_cols_changed ()499 private void on_n_cols_changed ()
432 {500 {
501 /* Ignore result set changes if we are disposed */
502 if (renderer == null)
503 return;
504
433 var n_cols = renderer.get_n_cols ();505 var n_cols = renderer.get_n_cols ();
434506
435 if (bin_state == ExpandingBinState.UNEXPANDED)507 if (bin_state == ExpandingBinState.UNEXPANDED)
436508
=== modified file 'unity-private/places/places-default-renderer.vala'
--- unity-private/places/places-default-renderer.vala 2010-09-22 12:04:58 +0000
+++ unity-private/places/places-default-renderer.vala 2010-10-01 09:55:56 +0000
@@ -51,8 +51,18 @@
51 Object ();51 Object ();
52 }52 }
5353
54 ~DefaultRenderer ()54 /* For some reason we must manually drop these in dispose() otherwise
55 * they end up leaked... And please note that finalize is not good enough
56 * either - so there is probably a ref cycle somewhere caused by all the
57 * actor.animate() calls... */
58 private override void dispose ()
55 {59 {
60 remove_actor (scroll);
61 remove_actor (search_empty);
62 remove_actor (section_empty);
63
64 /* Chain up */
65 base.dispose ();
56 }66 }
5767
58 private static double68 private static double
@@ -418,6 +428,7 @@
418 group.always_expanded = true;428 group.always_expanded = true;
419 }429 }
420 }430 }
431
421 }432 }
422 }433 }
423434
424435
=== modified file 'unity-private/places/places-view.vala'
--- unity-private/places/places-view.vala 2010-09-20 22:16:46 +0000
+++ unity-private/places/places-view.vala 2010-10-01 09:55:56 +0000
@@ -33,10 +33,10 @@
33 private Ctk.VBox content_box;33 private Ctk.VBox content_box;
34 private LayeredBin layered_bin;34 private LayeredBin layered_bin;
3535
36 public PlaceHomeEntry home_entry;36 public PlaceEntry home_entry;
37 public PlaceSearchBar search_bar;37 public PlaceSearchBar search_bar;
38 private Unity.Place.Renderer renderer;38 private Unity.Place.Renderer? renderer;
39 private unowned PlaceEntry? active_entry = null;39 private unowned PlaceEntry? active_entry = null;
4040
41 private bool is_showing = false;41 private bool is_showing = false;
4242
@@ -81,7 +81,10 @@
81 search_bar.entry.text.captured_event.connect (on_stage_event_captured);81 search_bar.entry.text.captured_event.connect (on_stage_event_captured);
82 search_bar.entry.text.activatable = true;82 search_bar.entry.text.activatable = true;
83 search_bar.entry.text.activate.connect (() => {83 search_bar.entry.text.activate.connect (() => {
84 renderer.activate_default (); 84 if (renderer is Clutter.Actor)
85 {
86 renderer.activate_default ();
87 }
85 });88 });
8689
87 layered_bin = new LayeredBin ();90 layered_bin = new LayeredBin ();
@@ -107,6 +110,7 @@
107 active_entry.active = false;110 active_entry.active = false;
108 }111 }
109 active_entry = null;112 active_entry = null;
113 remove_current_renderer ();
110 }114 }
111115
112 public void on_entry_view_activated (PlaceEntry entry, uint section_id)116 public void on_entry_view_activated (PlaceEntry entry, uint section_id)
@@ -126,30 +130,34 @@
126 entry.renderer_info_changed.connect (on_entry_renderer_info_changed);130 entry.renderer_info_changed.connect (on_entry_renderer_info_changed);
127 }131 }
128132
129 private void update_views (PlaceEntry entry, uint section_id=0)133 /* Fade out previous results view if we had one, and set
134 * this.renderer = null */
135 private void remove_current_renderer ()
130 {136 {
131 search_bar.set_active_entry_view (entry, 0, section_id);
132
133 /* Create the correct results view */
134 if (renderer is Clutter.Actor)137 if (renderer is Clutter.Actor)
135 {138 {
136
137 var anim = renderer.animate (Clutter.AnimationMode.EASE_OUT_QUAD,139 var anim = renderer.animate (Clutter.AnimationMode.EASE_OUT_QUAD,
138 300,140 300,
139 "opacity", 0);141 "opacity", 0);
140 anim.completed.connect ((a)=> {142
141 (a.get_object () as Clutter.Actor).destroy ();
142 });
143 layered_bin.remove_actor (renderer);143 layered_bin.remove_actor (renderer);
144 renderer = null;
144 }145 }
145146 }
147
148 private void update_views (PlaceEntry entry, uint section_id=0)
149 {
150 search_bar.set_active_entry_view (entry, 0, section_id);
151
152 remove_current_renderer ();
153
154 /* Create the correct results view */
146 renderer = lookup_renderer (entry);155 renderer = lookup_renderer (entry);
156
147 layered_bin.add_actor (renderer);157 layered_bin.add_actor (renderer);
148 renderer.unref (); /* Because lookup_renderer returns it unfloating */
149 renderer.opacity = 0;158 renderer.opacity = 0;
150 renderer.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,159 renderer.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
151 "opacity", 255);160 "opacity", 255);
152
153 renderer.set_models (entry.entry_groups_model,161 renderer.set_models (entry.entry_groups_model,
154 entry.entry_results_model,162 entry.entry_results_model,
155 entry.entry_renderer_hints);163 entry.entry_renderer_hints);
156164
=== modified file 'unity/unity-layered-bin.vala'
--- unity/unity-layered-bin.vala 2010-09-02 19:19:10 +0000
+++ unity/unity-layered-bin.vala 2010-10-01 09:55:56 +0000
@@ -28,9 +28,9 @@
28 */28 */
29 public class LayeredBin : Ctk.Actor, Clutter.Container29 public class LayeredBin : Ctk.Actor, Clutter.Container
30 {30 {
31 private GLib.List<Clutter.Actor?> _children = null;31 private Gee.List<Clutter.Actor> _children = new Gee.LinkedList<Clutter.Actor>();
3232
33 public unowned GLib.List<Clutter.Actor?> children {33 public unowned Gee.List<Clutter.Actor> children {
34 get { return _children; }34 get { return _children; }
35 }35 }
3636
@@ -39,12 +39,17 @@
39 Object ();39 Object ();
40 }40 }
4141
42 ~LayeredBin ()42 private override void dispose ()
43 {43 {
44 foreach (Clutter.Actor child in _children)44 foreach (Clutter.Actor child in _children)
45 child.unparent ();45 {
46 child.unparent ();
47 }
4648
47 _children = null;49 _children.clear ();
50
51 /* Chain up */
52 base.dispose ();
48 }53 }
4954
50 construct55 construct
@@ -124,7 +129,7 @@
124 private void add (Clutter.Actor actor)129 private void add (Clutter.Actor actor)
125 {130 {
126 actor.set_parent (this);131 actor.set_parent (this);
127 _children.append (actor);132 _children.add (actor);
128133
129 queue_relayout ();134 queue_relayout ();
130135
@@ -157,30 +162,30 @@
157 private new void raise (Clutter.Actor actor, Clutter.Actor sibling)162 private new void raise (Clutter.Actor actor, Clutter.Actor sibling)
158 {163 {
159 if (sibling is Clutter.Actor &&164 if (sibling is Clutter.Actor &&
160 _children.index (sibling) != -1)165 _children.index_of (sibling) != -1)
161 {166 {
162 _children.remove (actor);167 _children.remove (actor);
163 _children.insert (actor, _children.index (sibling) + 1);168 _children.insert (_children.index_of (sibling) + 1, actor);
164 }169 }
165 else170 else
166 {171 {
167 _children.remove (actor);172 _children.remove (actor);
168 _children.append (actor);173 _children.add (actor);
169 }174 }
170 }175 }
171176
172 private new void lower (Clutter.Actor actor, Clutter.Actor sibling)177 private new void lower (Clutter.Actor actor, Clutter.Actor sibling)
173 {178 {
174 if (sibling is Clutter.Actor &&179 if (sibling is Clutter.Actor &&
175 _children.index (sibling) != -1)180 _children.index_of (sibling) != -1)
176 {181 {
177 _children.remove (actor);182 _children.remove (actor);
178 _children.insert (actor, _children.index (sibling) - 1);183 _children.insert (_children.index_of (sibling) - 1, actor);
179 }184 }
180 else185 else
181 {186 {
182 _children.remove (actor);187 _children.remove (actor);
183 _children.prepend (actor);188 _children.insert (0, actor);
184 }189 }
185 }190 }
186191
187192
=== modified file 'unity/unity-stripe-texture.vala'
--- unity/unity-stripe-texture.vala 2010-08-26 07:52:44 +0000
+++ unity/unity-stripe-texture.vala 2010-10-01 09:55:56 +0000
@@ -35,16 +35,16 @@
35 int width,35 int width,
36 int height);36 int height);
3737
38 public float radius { get; construct set; }
39
40 public StripeTextureOutlineFunc outline_paint_func;38 public StripeTextureOutlineFunc outline_paint_func;
4139
42 private Cairo.Surface? pattern;40 private Cairo.Surface? pattern;
4341
44 public StripeTexture (StripeTextureOutlineFunc? func)42 public StripeTexture (StripeTextureOutlineFunc? func)
45 {43 {
46 Object (radius:10.0f);44 Object ();
4745
46 /* Must not point to a lambda or non-static method on 'this'.
47 * It causes self-refs if it does */
48 outline_paint_func = rounded_outline;48 outline_paint_func = rounded_outline;
49 if (func != null)49 if (func != null)
50 outline_paint_func = func;50 outline_paint_func = func;
@@ -55,8 +55,10 @@
55 paint_func = paint_bg;55 paint_func = paint_bg;
56 }56 }
5757
58 public void rounded_outline (Cairo.Context cr, int width, int height)58 /* This method must be static in order to avoid self refs */
59 public static void rounded_outline (Cairo.Context cr, int width, int height)
59 {60 {
61 float radius = 10;
60 var x = 0;62 var x = 0;
61 var y = 0;63 var y = 0;
62 width -= 1;64 width -= 1;