This site has been retired. For up to date information, see handbook.gnome.org or gitlab.gnome.org.


[Home] [TitleIndex] [WordIndex

This is a project to reduce the amount of memory required for the desktop and for applications. The following sections are available:

Overview

The plan is to reduce the amount of memory that Gnome applications consume. Gnome is barely usable on a machine with 128 MB of RAM; contrast this with Windows XP, which is very snappy on such a configuration.

Why do you want to reduce memory consumption?

To begin hacking on memory reduction, one must break the problem down into many steps. There are a number of areas where the memory problem is exposed:

JohnMoser: Consider applications running for a long time to be impossible, especially if they spike resources.

(JohnMoser had a lot to say, didn't he?)

StephaneChauveau: Allocation a lot of small blocks with mmap instead of a large heap is probably a good idea.

How to measure the memory used?

First we need to know how to measure the memory used. Tool like ps are quite useless for that purpose, unless you know exactly what they mean. See this blog entry about memory usage with smaps. Also, other interesting posts, especially for newbies, are this and this. Andy Wingo has a nice article about reducing the memory footprint of Python applications here.

How is memory used?

Here we only consider memory that is allocated for application data; we don't consider (for now) the memory used for code.

JohnMoser: Interesting consideration, at least with ET_DYN (PIEs and libraries), the code is actually mmap()ed into memory. As long as you don't alter it (and you shouldn't, ever, under any circumstances), that area will be file-backed and exist as disk cache-- that is, it will be purged if not used and should be shared between processes mapping the same area in. This means that the code takes effectively zero memory. There's some for the memory mapping in the kernel, and some for the Global Offset Table (GOT) entries. So we can ignore that, to a degree. (JohnGilmore: This isn't true -- any shared library page that gets relocated by the dynamic linker will have been made writeable (copy-on-write) and will then have to either be maintained in RAM forever (OLPC) or swapped out to paging space on a hard drive. Pages are relocated either because the library wasn't prelinked to the address where it ended up mapped in; or because it refers to symbols from other libraries.)

The heap is what you malloc(). Most of an application's memory consumption is likely to be here. Tools like memprof and valgrind let you monitor the heap.

Gnome applications also use memory in other ways. Every GTK+ process has a block of shared memory that it uses to quickly communicate image data to the X server. See gnomecvs:gtk+/gdk/gdkrgb.c.

Also, all X clients use resources inside the server. A program like xrestop lets you monitor this usage. For example, Mozilla stores image data in web pages as pixmaps in the X server. That's why your X server balloons to 100 MB when viewing large, graphics-heavy web pages.

StephaneChauveau: There are also the non read-only pages that are allocated statically by each shared library. They contain all non-constant global data and the shared library address translation tables. Those pages are not shared between processes. I made a quick computation for gcalctool (on AMD64). That simple program uses 73 shared libraries that allocate a total of 13Mb of non-shared static data. I hope that I made a mistake somewhere.

JohnMoser: read the man page for ld for the --as-needed switch please. Apparently some people using or developing Ubuntu have discovered that they can shave a big chunk off the GNOME dependencies using this switch. This is apparently experimental; but has something to do with different libraries being needed on different platforms. linku.

Meeting logs

GTK+ team meeting log, 2005/Feb/21

Basic footprint

All applications in the desktop have a minimum memory footprint which is determined by the toolkit. For example, all GTK+ apps allocate memory for this:

BenMaurer reports that a trivial "Hello World" program in GTK+ 2.6 generates the following data in Valgrind:

That's 450 KB of data for a program that does nothing but paint a button! And that doesn't even include the code size. It also does not take into account the GdkRGB shared memory segments, which are 96K pixels per application. On machines with 24-bit displays, that's 400 extra KB per process.

[ Isn't this just the allocated data that was still allocated at exit? It doesn't count data that was used and then freed. If GTK cleaned up after itself properly, this value should be zero... so this value is just a lower bound on the memory consumption of hello world. I guess massiv would show a more accurate figure. ]

BenMaurer: Not really. First, I used ctrl+c to exit, so valgrind did not do anything to clean up gtk+. Second, remember that the OS is about to free everythnng mre efficently than we ever could. "cleaning up" is useless. For a lareger test case, massif is a better idea however.

A typical Gnome desktop has around 20 processes running all the time: gnome-session, gnome-settings-daemon, Nautilus, the panel, a bunch of applets, etc. So that's 20 times 850 KB, which amounts to 17 MB just for the footprint of the basic desktop components. This of course doesn't take into account each component's real data: file lists in Nautilus, images for applets, the panel's menus, the Metacity theme, etc.

JohnMoser: Looking into Position Independent Executables (PIEs), which are used on some platforms to allow address space layout randomization (ASLR) to do a better job, it may be possible to try and mitigate the applets to a degree. libc6/glibc is a PIE; if you chmod +x libc6.so, you can run it as a program! If the applets had an entry point as a library, and were compiled as PIEs, it may be possible to craft each applet to be able to run either as they are now (separate process) or as a plug-in which is loaded by gnome-panel, depending on a user option (and of course if the applet supports that). This could shave off some data, assuming that the applets have to devote a significant amount of heap space to setting up basic GTK+ structures just to set up a significantly smaller set of controls.

JohnGilmore: You can see what memory a running process is using by "cat /proc/nnn/smaps", where nnn is the process number. This will print serveral lines for each region of memory, listing the range of memory addresses, permissions, the filename of the file mapped here (if any), and then various sizes. Here is one section from the output for a Gnome Terminal process:

 00411000-004c4000 r-xp 00000000 fd:00 37009854   /usr/lib/libvte.so.9.1.5
 Size:               716 kB
 Rss:                188 kB
 Shared_Clean:         0 kB
 Shared_Dirty:         0 kB
 Private_Clean:      188 kB
 Private_Dirty:        0 kB
 004c4000-004c7000 rwxp 000b3000 fd:00 37009854   /usr/lib/libvte.so.9.1.5
 Size:                12 kB
 Rss:                  8 kB
 Shared_Clean:         0 kB
 Shared_Dirty:         0 kB
 Private_Clean:        0 kB
 Private_Dirty:        8 kB

This shows that parts of this library used by Gnome Terminal have been mapped into two address ranges (first for the read-only memory (r-xp), then for the read-write (rwxp)). There's 716 kB of read-only, of which 188 kB is resident and is private and clean (not written to). The rest of the 716 kB is paged out. There's 12 kB of writeable memory, of which 8 kB is resident, it's private rather than shared with another process, and it's dirty because it has been modified since being read in from disk.

When reducing memory footprints for the OLPC, keeping track of the Private_Dirty memory is key, because it can never be swapped out. The OLPC has no hard drive, and doesn't swap to flash (to avoid wearing out the flash rapidly). Clean pages can be discarded at any time, because they can be reread from the file when needed; dirty pages must be kept by the kernel.

In the Gnome Terminal output, the biggest chunk is this entry, which represents the heap:

 089a9000-09f5d000 rwxp 089a9000 00:00 0
 Size:             22224 kB
 Rss:               4720 kB
 Shared_Clean:         0 kB
 Shared_Dirty:         0 kB
 Private_Clean:      528 kB
 Private_Dirty:     4192 kB

Here, 4.7 MB is resident, almost all of it is dirty, and there's 22 MB allocated but not resident.

Hmm, here are some big chunks too -- though they aren't resident, they take up a lot of virtual memory and are not actually being used by this ordinary terminal emulator. Why is Gnome Terminal loading Korean and Japanese fonts?

 b36a5000-b408d000 r--p 00000000 fd:00 37227941   /usr/share/fonts/korean/TrueType/gulim.ttf
 Size:             10144 kB
 Rss:                 16 kB
 Shared_Clean:        16 kB
 Shared_Dirty:         0 kB
 Private_Clean:        0 kB
 Private_Dirty:        0 kB
 b412f000-b4885000 r--p 00000000 fd:00 37227497   /usr/share/fonts/japanese/TrueType/sazanami-gothic.ttf
 Size:              7512 kB
 Rss:                 44 kB
 Shared_Clean:        36 kB
 Shared_Dirty:         0 kB
 Private_Clean:        8 kB
 Private_Dirty:        0 kB

Please don't take out the fonts that allow me to read the names of the artists/songs of some of my music instead of seeing files "named" iAAA{!r!{{.ogg Why use unicode at all if you're only interested in 7-bit ASCII? (rhetorical question)


CategoryOptimization


2024-10-23 11:17