i was poking around trying to figure out the memory use of dconf. it has been one of my goals to ensure that there is only a very small per-application footprint (ie: writable memory). i’m ok with a slightly larger shared read-only footprint since this is shared between all applications.
here is what i see in the “smaps” for a small test application linked against and using dconf:
b7936000-b7944000 r-xp 00000000 08:01 54510 /opt/gnome/lib/libdconf.so.0.0.0 Size: 56 kB Rss: 56 kB Shared_Clean: 40 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 16 kB b7944000-b7945000 rw-p 0000d000 08:01 54510 /opt/gnome/lib/libdconf.so.0.0.0 Size: 4 kB Rss: 4 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 4 kB
so 4kb of memory is mapped read-write as a result of linking against libdconf. i can deal with that since i pretty much have to deal with that. as far as i know, there is absolutely no way to get rid of all relocations.
what worries me, though, is the first bit. even though this memory is mapped read-only, it is mapped private rather than shared. i always assumed that readonly/private mappings are the same as their readonly/shared counterparts (for the same reason that a readwrite/private mapping is the same as a readwrite/shared mapping up to the point that you perform your first copy-on-write).
in the first section, however, you see
Shared_Clean: 40 kB ... Private_Dirty: 16 kB
what’s this private dirty stuff? does this mean that each application using the library has a private 16kb of memory in use because of it? why does this happen at all with read-only mappings?
does anyone know what’s going on here?
(ps: two copies of the test application are running)
update: problem solved
i did a strace and discovered something tricky was going on:
... open("/opt/gnome/lib/libdconf.so.0", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\3\3\1\320;"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=140341, ...}) = 0 mmap2(NULL, 60548, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7889000 .... mprotect(0xb7889000, 57344, PROT_READ|PROT_WRITE) = 0 mprotect(0xb7889000, 57344, PROT_READ|PROT_EXEC) = 0 ...
what is this?
you can pretty much guess that mprotect() isn’t being called and then undone for no reason at all. there are writes going on there. sure enough, it’s the dynamic linker doing relocations.
but doesn’t libtool build my library with -fpic?
libtool is smart enough to know that .c files built to be part of a shared library need -fpic.
in my case, all of the backends for dconf are in a separate directory. i manage this by building that separate directory as a static library and then linking that into the dconf shared library. libtool doesn’t have smarts to figure this “will become part of a shared library” thing out beyond the first level of indirection.
one tweak to the CFLAGS for the static library and now everything is good :)
What do you mean “what’s this private dirty stuff”? It’s where the process keeps its pr0n!
Ok, sorry for the very bad joke, I just couldn’t resist.
Its always a good idea to keep your Privates clean. Hygenic.
:)
It is probably due to text relocations needed during dynamic linking:
http://www.google.com/codesearch?hl=en&q=+package:glibc+mprotect+show:ND-cjd34PJs:_kqcB-1Z7Jc:WkjYql58S4Q&sa=N&cd=29&ct=rc&cs_p=http://ftp.gnu.org/gnu/glibc/glibc-2.2.4.tar.gz&cs_f=glibc-2.2.4/elf/dl-reloc.c#a0
Do you perhaps have const structures/arrays that contain pointers to other structures or strings?
One more note: if it is the “const array of strings” problem, the usual solution is to have one const char array containing all the relevant strings separated by NUL bytes, and a second array giving the offsets of each string in the previous array.
This is fine up unless you need to expose arrays of strings to other libraries or the app.