[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Memory Usage in KDE (LONG)
From:       Waldo Bastian <bastian () suse ! de>
Date:       1999-10-18 12:50:24
[Download RAW message or body]

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/<PID>/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 <program_name>". 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)

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic