Yesterday I hacked up a glib patch to track memory
use. Its a g_malloc replacement that has some memory type tracking features which are nicely integrated with common glib/gtk+ types.
All the app has to do is call g_mem_set_vtable(glib_mem_tracker_table)
the first thing you do in main, and then calling g_mem_track() will
write the full allocation information into a file called
“memtrack.dat” in the current directory. You can then use a separate
app to analyze this file at your leasure.
So, what does this give us for Nautilus? I started it, browsed
around a bit and ended with a window showing my homedir (which has about 600 files), then I triggered the memory dump. The
memory use summary is now:
./analyze-memdump -s nautilus-run-with-home.dat total size: 5201628 unknown type: 1609963 strings: 914293 objects: 495264 slice: 559180 list headers: 165400 pixbuf data: 1457528
So, we’re using about 5 megs of heap. Almost 1 meg of this is
strings, 1.5 meg is pixbufs. Lets look at what sort of strings we have:
./analyze-memdump -z nautilus-run-with-home.dat file nautilus-file.c: 254163 bytes file pango-layout.c: 180279 bytes file gfileutils.c: 111728 bytes file gstrfuncs.c: 63963 bytes file gunicollate.c: 40120 bytes file gnome-vfs-file-info.c: 32965 bytes file gtkicontheme.c: 29314 bytes file gnome-vfs-mime-info-cache.c: 24787 bytes file gtkrc.c: 21428 bytes file gconf-value.c: 20343 bytes file gdataset.c: 20222 bytes file nautilus-icon-canvas-item.c: 12314 bytes ... string of size 64: 2020 (129280 bytes) string of size 2048: 53 (108544 bytes) string of size 1024: 106 (108544 bytes) string of size 128: 147 (18816 bytes) string of size 20: 868 (17360 bytes) string of size 512: 33 (16896 bytes) string of size 19: 869 (16511 bytes) string of size 18: 839 (15102 bytes) string of size 11: 1340 (14740 bytes) string of size 60: 238 (14280 bytes) string of size 16: 844 (13504 bytes) string of size 14: 923 (12922 bytes) ...
Lots of strings in nautilus-file.c, lets look into that file:
./analyze-memdump -f nautilus-file.c nautilus-run-with-home.dat For the file 'nautilus-file.c': total size: 254163 unknown type: 0 strings: 254163 objects: 0 slice: 0 list: 0 pixbuf data: 0 block size 2048: 53 allocations (108544 bytes) block size 1024: 106 allocations (108544 bytes) block size 512: 32 allocations (16384 bytes) block size 256: 7 allocations (1792 bytes) block size 128: 4 allocations (512 bytes) block size 64: 9 allocations (576 bytes) block size 54: 1 allocations (54 bytes) block size 48: 1 allocations (48 bytes) line 2637: 5 bytes (1 allocations) line 2675: 9 bytes (1 allocations) line 4731: 32 bytes (2 allocations) line 221: 37 bytes (8 allocations) line 1397: 76 bytes (4 allocations) line 284: 211 bytes (6 allocations) line 1437: 17333 bytes (1001 allocations) line 6063: 236460 bytes (217 allocations)
A lot of large strings, and they seem to all be from line 6063 of
nautilus-file.c. Looking at this code reveals that this is the memory
used for storing the first bit of text files so that we can show the
text in the icon. We only save the text in the first 80×24 chars of
the file, but perhaps we could save less of it and reload the data for
the uncommon case of a large icon that needs more text.
The string use in pango-layout.c isn’t suprising, as Nautilus stores
the PangoLayouts for each label in the icon view to be able to draw it
quickly without having to re-layout. Unfortunately PangoLayout also
stores a copy of the actual strings, which we don’t really need.
Looking back at the totals we have 0.5 meg of GObjects (although this
doesn’t include memory allocated by the objects). Lets have a look at
that:
./analyze-memdump -o nautilus-run-with-home.dat type 'NautilusVFSFile': 121080 bytes, 1009 objects type 'PangoLayout': 88060 bytes, 1295 objects type 'NautilusIconCanvasItem': 32256 bytes, 504 objects type 'GtkAccelLabel': 28880 bytes, 190 objects type 'GstPadTemplate': 27512 bytes, 362 objects type 'PangoCairoFcFont': 24864 bytes, 111 objects type 'GstElementFactory': 23856 bytes, 213 objects type 'GtkImage': 15808 bytes, 152 objects type 'GtkImageMenuItem': 15100 bytes, 151 objects type 'GtkSeparatorMenuItem': 15072 bytes, 157 objects type 'ClearlooksStyle': 14388 bytes, 11 objects type 'GdkWindowImplX11': 9100 bytes, 91 objects type 'GdkPixbuf': 8320 bytes, 160 objects type 'GdkWindow': 8008 bytes, 91 objects type 'GtkAction': 7208 bytes, 106 objects type 'GtkRcStyle': 6640 bytes, 20 objects ...
Lots of NautilusFiles, PangoLayouts and icons which is hardly
surprising. However, we also have a lot of accel-labels, and menu
items. This is from the menu in the window and the hidden menu in the
desktop window. I wonder what the gstreamer objects are from though.
Another way to look at memory use is to look at what files allocate a
lot of memory:
./analyze-memdump -p nautilus-run-with-home.dat Per-file memory use: No file info: 201536 file 'gdk-pixbuf.c': 1457837 file 'gtype.c': 606802 file 'glyphstring.c': 453448 file 'ghash.c': 305840 file 'pango-layout.c': 274576 file 'nautilus-file.c': 254163 file 'gnome-vfs-file-info.c': 146309 file 'glist.c': 131400 file 'gfileutils.c': 124571 file 'gtkicontheme.c': 97906 file 'nautilus-icon-canvas-item.c': 97538 file 'gclosure.c': 75316 file 'gstrfuncs.c': 71390 file 'gsignal.c': 69152 file 'gdataset.c': 63758 file 'garray.c': 63104 file 'fonts.c': 49232 file '../glib/gbsearcharray.h': 48972 file 'pango-item.c': 44640 ...
Here we also see the PangoLayouts using a lot of memory. Not only in
pango-layout.c (which is the strings), but also in glyphstring.c which
is the data from the PangoLayouts that I’m actually interested in. It
seems to be about twice the size as the strings though, so its not
very compactly stored. It would be interesting if one could take a
layouted PangoLayout and turn it into a lean platform-specific render
object that you could only render, and nothing else. That way i could
throw away the PangoLayout when it was done measuring the string. It
could also possibly store the glyph strings in a more compact way
(PangoGlyphInfo looks a bit large). Or maybe I should just bite the bullet and re-layout when drawing?
To test this stuff you have to apply these patches for glib and
gtk,
and then you have to rebuild your app and all glib-using libraries it
uses. The analyzer app is
here.
If you are interested in Nautilus you can download the
memory dump I used and play with it. It should work on any 32bit little-endian system.
Can you sign up gnome as a 2006 Google Summer of Code mentor organization? http://code.google.com/soc/
Awesome post on nautilus! I’ve been waiting for Federico to do something similar and you beat him to it.
What a awesome post – nice analyses
I modified the glib patch to work with version 2.8.5. It can be found here
http://jimmyk.org/drop/glib-mem-tracker.patch