From kde-core-devel Mon Oct 18 12:50:24 1999 From: Waldo Bastian Date: Mon, 18 Oct 1999 12:50:24 +0000 To: kde-core-devel Subject: Memory Usage in KDE (LONG) X-MARC-Message: https://marc.info/?l=kde-core-devel&m=94025784409400 Hiya, I would like to start this mail with my apologies to Stephan Kulow. When he said at KDE-Two that each KDE application needs at least 800Kb, I accused him of looking at the wrong numbers. Unfortunately I was wrong. My apologies for that. This weekend I have been measuring the memroy usage of KDE applications because I wanted to check the memory usage of mmaps within KSycoca. For this measurement I have used a current (18-10-99) snapshot of the CVS HEAD. The compiler used is "gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)". I have added to kdelibs/kdetest the program 'kmemtest' which you can use to verify my measurements. With this program I have been measuring two things. 1) I have been measuring the memory usage according to the "Data" entry in /proc//status. This is an accurate representation of the amount of memory your process allocates with 'malloc' and 'new' and which gets actually used. 2) I have been measuring the impact of launching an additional instance of an application on the total memory usage of my system. I have measured the total memory usage of my system according to the "memory used without buffers and without cache" entry of the "free" utility. This information can also be obtained from /proc/meminfo by taking the "Mem:/used:" entry and subtracting both "Mem:/buffers:" and "Mem:/cached:". I have compared the total memory usage when a single applications is running 5 times with the total memory usage when this same application is running 15 times. Simple application linked against difference libraries ========================================== I now took a look at an application which basically consisting of a malloc of 10K and a sleep() statement. I linked against libqt, libkdecore and libkdeui: Measured according to method 1) the size of the Data segment is 84K with 24K reserved for the Stack. Measured according to method 2) a single instantiation of this very simple program needs approx. 1895K of additional memory. I then relinked the program to only link against libqt and libkdecore: The memory usage according to method 1) did not change. The memory usage according to method 2) dropped to approx. 1605K. Conclusion: -------- Each additional instance of an application linked against kdeui requires an additional 290K of memory. kdeui with exception handling vs. kdeui without eception handling. ===================================================== I was very curious why linking (without even using it!) against a library requires so much memory in each process making use of this library. I measured the effect of compiling kdeui without RTTI and the effect of compiling kdeui without support for exceptions. I did not find any significant difference in memory usage with ot without RTTI. When I linked my application against a kdeui compiled without exception handling (-fno-exceptions) I got the following results: The memory usage according to method 1) did not change. (82K data, 24K stack) The memory usage according to method 2) became approx. 1675K. Conclusion: -------- Exception handling within kdeui is responsible for an increase in the memory usage of approx. 220Kb for every instance of an application linked against kdeui. How much memory dow a library require for exception-handling? ===================================================== Playing around with other libraries (most notably kdecore and libqt) I managed to find out how much memory is needed for in each insatnce which links against the library. Take e.g. a look at the output of "objdump --headers libkdeui.so.3.0.0": (libkdecore from _current_ CVS HEAD) libkdeui.so.3.0.0: file format elf32-i386 Sections: Idx Name Size VMA LMA File off Algn 0 .hash 000094c8 00000094 00000094 00000094 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .dynsym 000152d0 0000955c 0000955c 0000955c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .dynstr 00027566 0001e82c 0001e82c 0001e82c 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .gnu.version 00002a5a 00045d92 00045d92 00045d92 2**1 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .gnu.version_d 00000038 000487ec 000487ec 000487ec 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .gnu.version_r 00000050 00048824 00048824 00048824 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .rel.data 00014650 00048874 00048874 00048874 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .rel.eh_frame 00008390 0005cec4 0005cec4 0005cec4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 8 .rel.gcc_except_table 00013818 00065254 00065254 00065254 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .rel.got 00002178 00078a6c 00078a6c 00078a6c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 10 .rel.ctors 00000190 0007abe4 0007abe4 0007abe4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .rel.plt 00005090 0007ad74 0007ad74 0007ad74 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 12 .init 00000031 0007fe10 0007fe10 0007fe10 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .plt 0000a130 0007fe44 0007fe44 0007fe44 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 14 .text 000d162e 00089f80 00089f80 00089f80 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 15 .fini 0000001c 0015b5b0 0015b5b0 0015b5b0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 16 .rodata 000080a8 0015b5e0 0015b5e0 0015b5e0 2**5 CONTENTS, ALLOC, LOAD, READONLY, DATA 17 .data 0000b944 001646a0 001646a0 001636a0 2**5 CONTENTS, ALLOC, LOAD, DATA 18 .gcc_except_table 00009dd4 0016ffe4 0016ffe4 0016efe4 2**2 CONTENTS, ALLOC, LOAD, DATA 19 .eh_frame 0002c47c 00179db8 00179db8 00178db8 2**2 CONTENTS, ALLOC, LOAD, DATA 20 .ctors 000000d0 001a6234 001a6234 001a5234 2**2 CONTENTS, ALLOC, LOAD, DATA 21 .dtors 00000008 001a6304 001a6304 001a5304 2**2 CONTENTS, ALLOC, LOAD, DATA 22 .got 00003910 001a630c 001a630c 001a530c 2**2 CONTENTS, ALLOC, LOAD, DATA 23 .dynamic 000000c8 001a9c1c 001a9c1c 001a8c1c 2**2 CONTENTS, ALLOC, LOAD, DATA 24 .bss 00000954 001a9d00 001a9d00 001a8d00 2**5 ALLOC 25 .stab 00000fd8 00000000 00000000 001a8d00 2**2 CONTENTS, READONLY, DEBUGGING 26 .stabstr 00002840 00000000 00000000 001a9cd8 2**0 CONTENTS, READONLY, DEBUGGING 27 .comment 00000f03 00000000 00000000 001ac518 2**0 CONTENTS, READONLY 28 .note 000004ec 00000f03 00000f03 001ad41b 2**0 CONTENTS, READONLY 29 .rel.stab 00000020 000013f0 000013f0 001adf88 2**2 CONTENTS, READONLY, DEBUGGING In the above output entries which are labeled "DATA" but not "READONLY" are not shared across processes. That means that these entries are allocated for each instance of an application which links against this library. These entries are (size in brackets) .data (47428 bytes) .gcc_except_table (40404 bytes) .eh_frame (181372 bytes) .ctors (208 bytes) .dtors (8 bytes) .got (14608 bytes) .dynamic (200 bytes) Total size: 284228 bytes (277Kb) When compiling without support for exceptions the .gcc_execpt_table and .eh_frame sections are virtually empty (4 bytes total). Size needed for exception support: 221776 bytes (216Kb) This is roughly in line with the above measurement which showed that the memory usage per instance dropped with 220 Kb when kdeui was compiled without exception support. Conclusion: --------- The .gcc_except_table and .eh_frame sections in a library reflect the overhead for exception handling for each instance of an application linked against this library. Overview of exception handling overhead in libraries =========================================== The following list shows the exception handling overhead in each library in kdelibs as well as for Qt. libqt.so.2.1.0 total = 700.4Kb (717168 bytes) libkdeui.so.3.0.0 total = 216.6Kb (221776 bytes) libkded.so.1.0.0 total = 212.7Kb (217784 bytes) libkpartsui.so.1.0.0 total = 179.6Kb (183936 bytes) libkom.so.1.0.0 total = 164.4Kb (168320 bytes) libkdecore.so.3.0.0 total = 153.5Kb (157216 bytes) libkparts.so.1.0.0 total = 152.4Kb (156060 bytes) libkhtml.so.3.0.0 total = 144.4Kb (147844 bytes) libkio.so.3.0.0 total = 132.0Kb (135136 bytes) libkab.so.0.0.0 total = 131.7Kb (134812 bytes) libqk.so.1.0.0 total = 67.1Kb (68700 bytes) libkfile.so.3.0.0 total = 48.5Kb (49624 bytes) libcutesti.so.1.0.0 total = 27.6Kb (28236 bytes) libkjs.so.1.0.0 total = 26.0Kb (26668 bytes) libkformula.so.3.0.0 total = 25.6Kb (26248 bytes) libkspell.so.3.0.0 total = 18.3Kb (18744 bytes) libjscript.so.3.0.0 total = 15.0Kb (15348 bytes) libDCOP.so.1.0.0 total = 9.0Kb (9224 bytes) libkjava.so.1.0.0 total = 7.6Kb (7792 bytes) libkimgio.so.3.0.0 total = 2.5Kb (2608 bytes) libmediatool.so.3.0.0 total = 2.0Kb (2032 bytes) Conclusion: --------- Exception handling causes more overhead than CORBA ever did. More importantly it causes overhead for each and every instance of an application regardless whether it uses exceptions or not. Testing yourself ============= I have added a program kmemtest in kdelibs/kdetest. When you do measurements be sure to: * Kill all programs which aren't completely idle (inetd / crond / kmail?) * Have enough memory and swap. How to proceed: compile kmemtest (it links by default against qt, kdecore and kdeui) * run ./kmemtest and press Ctrl-C when it says 'Sleeping' * run ".libs/kmemtest all": this allocates all your memory and causes unused memory to be cleaned up/swapped out. * run ".libs/kmemtest launch": This starts itself up 15 times. At the end it will show you what /proc/self/status says about its memory consumption and what the actual measured memory consumption was. If it takes longer than about 2-4 tries before your memory usage has been stabilized you probably have some process running which you should kill first. * Wait patiently and don't touch your computer while kmemtest is running. At the end it will report the average memory usage for 1 instance of kmemtest and will fall asleep. * Don't forget to kill kmemtest (and lt-kmemtest) when you are done. You can also test the memory usage of other programs by running "kmemtest launch ". Be aware that this will try to startup your program 15 times! (So this will fail with e.g. kmail) Conclusions & Recommendation: =========================== * The overhead of exception handling is huge. * Qt and KDE should be compiled without support for exception handling. * The use of exceptions is depreciated. * Applications or libraries which need exception handling should enable it for themselves and make sure not to throw any exceptions to code which does not support it, including Qt. (Take expecially care of signals/slots and virtual functions)