Discussion:
a tool for debugging memory leaks? for ARM and OS-Linux
(too old to reply)
nass
2007-09-27 06:09:09 UTC
Permalink
Hello everyone, i'm observing how an embedded application i'm writing
is working 'in time', as the embedded system it's going to be in
operation 24/7...

the application is an algorithm running in a loop, reading through
drivers some pin inputs, doing some processing and sending the results
to another application (GUI), doing some logging, and driving (through
drivers again) some pin outputs.

using the command 'top' i see that the %memory used by this
application is slowly but steadily increasing...
i know that there is a suite of debugging memory problems called
Valgrind, but unfortunately they do not offer ARM (32bit) support
yet..

is there another program i could consider that could tell me about
memory leaks? any other pointers that might help me?
thank you for your advice.
nass
Paul Pluzhnikov
2007-09-28 00:16:13 UTC
Permalink
Post by nass
using the command 'top' i see that the %memory used by this
application is slowly but steadily increasing...
This in itself does not always imply that there is a leak.
You could have an ever-expanding data structure, or heap
fragmentation.
Post by nass
i know that there is a suite of debugging memory problems called
Valgrind, but unfortunately they do not offer ARM (32bit) support
yet..
There is a *ton* of malloc-debug libraries. You don't need VG just
to find memory leaks. Just google for "debug malloc", and link one
into your program.

Your other approach is to compile the code for Linux/x86, and link in
a "simulator" for parts that read the hardware. Then you can use any
of the tools available for Linux/x86 -- VG, Purify, Insure++, etc.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
nass
2007-10-01 07:50:55 UTC
Permalink
Post by Paul Pluzhnikov
Post by nass
using the command 'top' i see that the %memory used by this
application is slowly but steadily increasing...
This in itself does not always imply that there is a leak.
You could have an ever-expanding data structure, or heap
fragmentation.
yes an ever expanding data structure, i know i do not have. still is
there a way to check that too? smth like i'll attach a gdb server to
the target machine, and check variable sizes at the time of the
pause.... is it possible? but what is heap fragmentation?
Post by Paul Pluzhnikov
Post by nass
i know that there is a suite of debugging memory problems called
Valgrind, but unfortunately they do not offer ARM (32bit) support
yet..
There is a *ton* of malloc-debug libraries. You don't need VG just
to find memory leaks. Just google for "debug malloc", and link one
into your program.
Your other approach is to compile the code for Linux/x86, and link in
a "simulator" for parts that read the hardware. Then you can use any
of the tools available for Linux/x86 -- VG, Purify, Insure++, etc.
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Thank you
nass
2007-10-01 14:21:03 UTC
Permalink
Post by nass
Post by Paul Pluzhnikov
Post by nass
using the command 'top' i see that the %memory used by this
application is slowly but steadily increasing...
This in itself does not always imply that there is a leak.
You could have an ever-expanding data structure, or heap
fragmentation.
yes an ever expanding data structure, i know i do not have. still is
there a way to check that too? smth like i'll attach a gdb server to
the target machine, and check variable sizes at the time of the
pause.... is it possible? but what is heap fragmentation?
Post by Paul Pluzhnikov
Post by nass
i know that there is a suite of debugging memory problems called
Valgrind, but unfortunately they do not offer ARM (32bit) support
yet..
There is a *ton* of malloc-debug libraries. You don't need VG just
to find memory leaks. Just google for "debug malloc", and link one
into your program.
Your other approach is to compile the code for Linux/x86, and link in
a "simulator" for parts that read the hardware. Then you can use any
of the tools available for Linux/x86 -- VG, Purify, Insure++, etc.
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Thank you
yes there is something i haven't noted and it might be important...
i only use a few 'new' operators in the constructors (and
corresponding 'delete' operators in the destructors) so there is no
forseeable expanding allocation of memory from the heap during
runtime..... or is there? this sounds stupid and desperarte but
really: is it possible that if i replace all the new in the
constructors with normal variables... i can get passed the memory
leakage problems?
Paul Pluzhnikov
2007-10-01 19:44:44 UTC
Permalink
Post by nass
yes there is something i haven't noted and it might be important...
i only use a few 'new' operators in the constructors (and
corresponding 'delete' operators in the destructors) so there is no
forseeable expanding allocation of memory from the heap during
runtime..... or is there?
Actually, there is.

Perhaps you've neglected to follow the advice from
Effective-C++ Item 11, aka the 'Rule of three' ?
See http://www.ddj.com/cpp/184401400

Also, 'new' is far from being the only way you can leak memory --
there are many other ways to do that. For example:

while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}

or

while (p = receive_packet()) {
pthread_t tid;
pthread_create(&tid, 0, func, p);
// Oops -- forgot to join the thread
}

etc. etc.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
nass
2007-10-02 09:10:35 UTC
Permalink
Post by Paul Pluzhnikov
Post by nass
yes there is something i haven't noted and it might be important...
i only use a few 'new' operators in the constructors (and
corresponding 'delete' operators in the destructors) so there is no
forseeable expanding allocation of memory from the heap during
runtime..... or is there?
Actually, there is.
Perhaps you've neglected to follow the advice from
Effective-C++ Item 11, aka the 'Rule of three' ?
Seehttp://www.ddj.com/cpp/184401400
hm, ok the 'rule of three' seems fair enough but it seems to me it is
important when you copy and destroy objects at runtime...
i do not destroy any object at run time, i instantiate some objects in
the initialization stages and keep the running for ever. do the rule
of three still apply???
Post by Paul Pluzhnikov
Also, 'new' is far from being the only way you can leak memory --
while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}
also in such cases, p is not free'd by 'me' but it does get freed on
exit from functions... does it not?
Post by Paul Pluzhnikov
or
while (p = receive_packet()) {
pthread_t tid;
pthread_create(&tid, 0, func, p);
// Oops -- forgot to join the thread
}
etc. etc.
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Azazel
2007-10-02 14:45:21 UTC
Permalink
Post by nass
Post by Paul Pluzhnikov
Post by nass
yes there is something i haven't noted and it might be important...
i only use a few 'new' operators in the constructors (and
corresponding 'delete' operators in the destructors) so there is no
forseeable expanding allocation of memory from the heap during
runtime..... or is there?
Actually, there is.
Perhaps you've neglected to follow the advice from
Effective-C++ Item 11, aka the 'Rule of three' ?
Seehttp://www.ddj.com/cpp/184401400
hm, ok the 'rule of three' seems fair enough but it seems to me it is
important when you copy and destroy objects at runtime...
i do not destroy any object at run time, i instantiate some objects in
the initialization stages and keep the running for ever. do the rule
of three still apply???
Post by Paul Pluzhnikov
Also, 'new' is far from being the only way you can leak memory --
while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}
also in such cases, p is not free'd by 'me' but it does get freed on
exit from functions... does it not?
strdup returns a dynamically allocated copy of its argument, which must
be freed by the caller.
--
Az.

www: http://www.azazel.net/
pgp: http://www.azazel.net/~azazel/az_key.asc
Paul Pluzhnikov
2007-10-03 03:42:48 UTC
Permalink
Post by nass
Post by Paul Pluzhnikov
Perhaps you've neglected to follow the advice from
Effective-C++ Item 11, aka the 'Rule of three' ?
hm, ok the 'rule of three' seems fair enough but it seems to me it is
important when you copy and destroy objects at runtime...
i do not destroy any object at run time, i instantiate some objects in
the initialization stages and keep the running for ever. do the rule
of three still apply???
Probably. You may not be copying objects intentionally, but compiler
may be doing that for you without you realizing that.

Declare a private copy constructor and operator=(), but don't
implement them. If your code still compiles and links, then objects
were not copied/assigned. If it doesn't, then they were.
Post by nass
Post by Paul Pluzhnikov
while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}
also in such cases, p is not free'd by 'me' but it does get freed on
exit from functions... does it not?
Not at all.

The mere fact that you think it might somehow get free()d,
shows utter lack of understanding of dynamic memory management.
You should probably seek immediate help of a local 'C' wizard.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
nass
2007-10-03 12:36:25 UTC
Permalink
Post by Paul Pluzhnikov
Post by nass
Post by Paul Pluzhnikov
Perhaps you've neglected to follow the advice from
Effective-C++ Item 11, aka the 'Rule of three' ?
hm, ok the 'rule of three' seems fair enough but it seems to me it is
important when you copy and destroy objects at runtime...
i do not destroy any object at run time, i instantiate some objects in
the initialization stages and keep the running for ever. do the rule
of three still apply???
Probably. You may not be copying objects intentionally, but compiler
may be doing that for you without you realizing that.
Declare a private copy constructor and operator=(), but don't
implement them. If your code still compiles and links, then objects
were not copied/assigned. If it doesn't, then they were.
Post by nass
Post by Paul Pluzhnikov
while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}
also in such cases, p is not free'd by 'me' but it does get freed on
exit from functions... does it not?
Not at all.
The mere fact that you think it might somehow get free()d,
shows utter lack of understanding of dynamic memory management.
You should probably seek immediate help of a local 'C' wizard.
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
im not referring to strdup exclusively. in fact im not using threads
and i dunno how to program them.
but do seriously local variables NOT get free'd on exit from function
calls??? so pointers declared locally do not get free'd?
i mean this is really important... is it not like that?
nass
Rainer Weikusat
2007-10-03 12:41:37 UTC
Permalink
[...]
Post by nass
Post by Paul Pluzhnikov
Post by nass
Post by Paul Pluzhnikov
while (p = receive_packet()) {
char *p = strdup(p->name); ...
// Oops -- forgot to free(p);
}
also in such cases, p is not free'd by 'me' but it does get freed on
exit from functions... does it not?
Not at all.
The mere fact that you think it might somehow get free()d,
shows utter lack of understanding of dynamic memory management.
You should probably seek immediate help of a local 'C' wizard.
[...]
Post by nass
im not referring to strdup exclusively. in fact im not using threads
and i dunno how to program them.
but do seriously local variables NOT get free'd on exit from function
calls??? so pointers declared locally do not get free'd?
'The pointer' and 'what the pointer points to' are two different
things. The storage (if any) used to hold the pointer value is freed
on exist of the definining function. But this does not extend to
whatever object may have been located at that particular address.
Paul Pluzhnikov
2007-10-03 14:23:05 UTC
Permalink
Post by nass
Post by Paul Pluzhnikov
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
[Please trim your replies just to the part you are replying to.]
Post by nass
im not referring to strdup exclusively. in fact im not using threads
and i dunno how to program them.
I didn't imply that you do. Merely that there are many different
ways to leak memory, besides calling new.
Post by nass
but do seriously local variables NOT get free'd on exit from function
calls??? so pointers declared locally do not get free'd?
i mean this is really important...
Yes, this really *is* important.

As Rainer Weikusat explained, there are two separate "things"
here -- the pointer itself, and the "thing" that it points to.

The pointer itself resides on the stack, occupies 4 bytes (on a
32-bit machine), and these 4 bytes are "released back to the system"
(popped off stack) when the function returns.

The "thing" that the pointer points to may reside on stack, in the
"global data" section, or in heap (strdup returns memory from heap).
It may occupy 0, 20, 4000, or even 2147483647 bytes, and it does
*not* get automatically "released back to the system" just because
the function returns.

[BTW, this is "C memory management 101" -- stuff that every competent
C (and C++) programmer should understand completely.]

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
nass
2007-10-03 16:08:14 UTC
Permalink
Post by Paul Pluzhnikov
Post by nass
Post by Paul Pluzhnikov
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
[Please trim your replies just to the part you are replying to.]
Post by nass
im not referring to strdup exclusively. in fact im not using threads
and i dunno how to program them.
I didn't imply that you do. Merely that there are many different
ways to leak memory, besides calling new.
Post by nass
but do seriously local variables NOT get free'd on exit from function
calls??? so pointers declared locally do not get free'd?
i mean this is really important...
Yes, this really *is* important.
As Rainer Weikusat explained, there are two separate "things"
here -- the pointer itself, and the "thing" that it points to.
The pointer itself resides on the stack, occupies 4 bytes (on a
32-bit machine), and these 4 bytes are "released back to the system"
(popped off stack) when the function returns.
The "thing" that the pointer points to may reside on stack, in the
"global data" section, or in heap (strdup returns memory from heap).
It may occupy 0, 20, 4000, or even 2147483647 bytes, and it does
*not* get automatically "released back to the system" just because
the function returns.
[BTW, this is "C memory management 101" -- stuff that every competent
C (and C++) programmer should understand completely.]
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
yeah yeah, thats true... i am an engineer.. not a programmer and im
struggling with c++ indeed.. learning really
i guess its time to some book.
thank you all for your help
nass
2007-10-04 17:13:59 UTC
Permalink
well, i have looked around my code quite a bit im freeing any
pointers /pointers to structures that i declare in local functions and
i still get inflation of the RAM used in the course of time (increase
of about 0.1% of 128MB RAM every half hour)...
so i turned to finding some leak detector... however i have not
google'd any that supports ARM...
any reference? valgring, ccmalloc, Boehm GC and LeakTrace don't do the
trick...

keep in mind that i am not using malloc/new at all during runtime...
only on the constructors. so i can not replace some malloc calls with
the leak libraries and expect to see results.. it's got to be
something like vagrind, that just runs the executable as an argument
to valgrind executable...

also i tried simulating the driver inputs by some constant values on
a x86 machine, but when i try to run the application with valgrind it
halts execution after a while...for no apparent reason...the
documentation does not help either..
ill replicate the output and get back and post it..
Paul Pluzhnikov
2007-10-05 02:57:59 UTC
Permalink
Post by nass
well, i have looked around my code quite a bit im freeing any
pointers /pointers to structures that i declare in local functions and
Huh? Free()ing things you didn't *allocate* is much worse than
not free()ing things you did -- the former will likely crash,
the latter will merely leak.
Post by nass
so i turned to finding some leak detector... however i have not
google'd any that supports ARM...
You don't need anything that specifically supports ARM.
Just use dmalloc, or mpatrol.
Post by nass
keep in mind that i am not using malloc/new at all during runtime...
If you are not using them (directly or indirectly), then you do
not need a leak detector -- no leak is possible without someone
calling malloc/realloc/calloc/memalign.
Post by nass
also i tried simulating the driver inputs by some constant values on
a x86 machine, but when i try to run the application with valgrind it
halts execution after a while...
Does the 'simulator' also halt without Valgrind?
If so, you've found a bug in it.
If not, and you aren't running out of memory, then you've found a
bug in VG (but that's unlikely).

Also, you do not need to run simulator under VG for very long;
if you are leaking, VG will find it after just a couple of
iterations.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
nass
2007-10-07 18:53:43 UTC
Permalink
well i did manage to find the main source of inflation of the memory..
some "new" was called during runtime on some object again and
again ...
i managed to figure it out from valgrind messages saying '[...] 1215
blocks DEFINITELY LOST in address [...]'
so i managed to identify that..other than that here is a print out of
what valgrind prints:

valgrind --gen-suppressions=yes --leak-check=yes controller
==21050== Memcheck, a memory error detector.
==21050== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et
al.
==21050== Using LibVEX rev 1732, a library for dynamic binary
translation.
==21050== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==21050== Using valgrind-3.2.3, a dynamic binary instrumentation
framework.
==21050== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et
al.
==21050== For more details, rerun with: -v
==21050==
--21050-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--21050-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--21050-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--21050-- DWARF2 CFI reader: unhandled CFI instruction 0:50


/*## once the program is running nothing appears on the console
window... this is the 'normal' running state... then i press ctrl+C..
and here is what follows..
btw ctrl+C is by no means a proper killing of the application.. there
is no handler for it... anyway here are the exit valgrind
messages...##*/


==21050==
==21050== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from
1)
==21050== malloc/free: in use at exit: 91,425 bytes in 427 blocks.
==21050== malloc/free: 1,482 allocs, 1,055 frees, 254,588 bytes
allocated.
==21050== For counts of detected errors, rerun with: -v
==21050== searching for pointers to 427 not-freed blocks.
==21050== checked 191,448 bytes.
==21050==
==21050== 68 bytes in 1 blocks are possibly lost in loss record 39 of
50
==21050== at 0x401DB0E: calloc (vg_replace_malloc.c:279)
==21050== by 0x400EBDC: _dl_allocate_tls (in /lib/ld-2.3.6.so)
==21050== by 0x42757BE: pthread_create@@GLIBC_2.1 (in /lib/tls/
libpthread-2.3.6.so)
==21050== by 0x4040843: __aio_enqueue_request (in /lib/tls/
librt-2.3.6.so)
==21050== by 0x40413EF: aio_write (in /lib/tls/librt-2.3.6.so)
==21050== by 0x805B973: LogBase::AsynchWriteLine() (logger.cpp:531)
==21050== by 0x805B375: LogBase::logUpdate() (logger.cpp:442)
==21050== by 0x806A499: MainObj::Update() (core.cpp:631)
==21050== by 0x806CCB2: MainObj::Run() (core.cpp:1595)
==21050== by 0x806DBFD: main (main.cpp:81)
==21050==
==21050== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- y
{
<insert a suppression name here>
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.1
fun:__aio_enqueue_request
fun:aio_write
fun:_ZN7LogBase15AsynchWriteLineEv
fun:_ZN7LogBase9logUpdateEv
fun:_ZN7MainObj6UpdateEv
fun:_ZN7MainObj3RunEv
fun:main
}
==21050==
==21050==
==21050== 6,986 bytes in 268 blocks are possibly lost in loss record
48 of 50
==21050== at 0x401CABB: operator new(unsigned) (vg_replace_malloc.c:
163)
==21050== by 0x40C7215: std::string::_Rep::_S_create(unsigned,
unsigned, std::allocator<char> const&) (in /usr/lib/libstdc++.so.
6.0.3)
==21050== by 0x40C79CB: std::string::_M_mutate(unsigned, unsigned,
unsigned) (in /usr/lib/libstdc++.so.6.0.3)
==21050== by 0x40C7CBD: std::string::assign(char const*, unsigned)
(in /usr/lib/libstdc++.so.6.0.3)
==21050== by 0x40C7E1B: std::string::operator=(char const*) (in /
usr/lib/libstdc++.so.6.0.3)
==21050== by 0x806DB4D: main (main.cpp:48)
==21050==
==21050== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ---- y
{
<insert a suppression name here>
Memcheck:Leak
fun:_Znwj
fun:_ZNSs4_Rep9_S_createEjjRKSaIcE
fun:_ZNSs9_M_mutateEjjj
fun:_ZNSs6assignEPKcj
fun:_ZNSsaSEPKc
fun:main
}
==21050==
==21050== LEAK SUMMARY:
==21050== definitely lost: 0 bytes in 0 blocks.
==21050== possibly lost: 7,054 bytes in 269 blocks.
==21050== still reachable: 84,371 bytes in 158 blocks.
==21050== suppressed: 0 bytes in 0 blocks.
==21050== Reachable blocks (those to which a pointer was found) are
not shown.
==21050== To see them, rerun with: --leak-check=full --show-
reachable=yes


that's pretty much it...
after 3 days of constant running the memory inflated again ..from 1.2
to 1.3 % of the memory.. still looking around.. for bugs
nass
Paul Pluzhnikov
2007-10-07 21:27:04 UTC
Permalink
Post by nass
well i did manage to find the main source of inflation of the memory..
some "new" was called during runtime on some object again and
again ...
Mis-information #1 -- earlier you stated that you didn't call
malloc/new at runtime, only during initialization.

Now you've found that you were calling new at runtime after all.
Post by nass
==21050== malloc/free: 1,482 allocs, 1,055 frees, 254,588 bytes
"proves" that you continue to call malloc/free at runtime (unless
all 1055 calls to free() happened during initialization, which
is somewhat unlikely).
Post by nass
==21050== 68 bytes in 1 blocks are possibly lost in loss record 39 of 50
==21050== at 0x401DB0E: calloc (vg_replace_malloc.c:279)
==21050== by 0x400EBDC: _dl_allocate_tls (in /lib/ld-2.3.6.so)
Mis-information #2 -- earlier you stated that you aren't using
threads, but in fact you *are* using them, although indirectly.
Post by nass
==21050== 6,986 bytes in 268 blocks are possibly lost in loss record 48 of 50
==21050== at 0x401CABB: operator new(unsigned) (vg_replace_malloc.c:163)
==21050== by 0x40C7215: std::string::_Rep::_S_create(...)
==21050== by 0x40C79CB: std::string::_M_mutate(...)
==21050== by 0x40C7CBD: std::string::assign(...)
==21050== by 0x40C7E1B: std::string::operator=(char const*)
==21050== by 0x806DB4D: main (main.cpp:48)
...
Post by nass
after 3 days of constant running the memory inflated again ..from 1.2
to 1.3 % of the memory.. still looking around.. for bugs
It is likely that the above 'possible leak' is in fact real; but
it's hard to tell what exactly is going on without knowing what
happens to the string assigned on line 48 of main.cpp

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
a***@gmail.com
2020-07-29 08:45:05 UTC
Permalink
I managed to figure it out from Valgrind messages saying '[...] 1215
can you please let me know, how did you manage to execute Valgrind on the ARM Device?
Loading...