To LUGNET HomepageTo LUGNET News HomepageTo LUGNET Guide Homepage
 Help on Searching
 
Post new message to lugnet.robotics.rcx.legosOpen lugnet.robotics.rcx.legos in your NNTP NewsreaderTo LUGNET News Traffic PageSign In (Members)
 Robotics / RCX / legOS / 2734
2733  |  2735
Subject: 
Re: detecting memory leaks
Newsgroups: 
lugnet.robotics.rcx.legos
Date: 
Tue, 16 Jul 2002 03:26:14 GMT
Viewed: 
2383 times
  
I've been experimenting with memory leak detection in the wake of recent
discussions, and have some additional thoughts, including a potential
kernel patch issue.  This msg is a bit long, appologies.

The proposed method of checking for memory leaks within a program is to
store a free memory value obtained from mm_free_mem() (in mm.c) when the
program is in a known good state (for instance, before dynamic
allocation has begun), and later to take another reading to compare.
There are several caveats to note.

The first and potentially worst is the mm_free_mem() was not written for
this purpose.  The only call to mm_free_mem() in the kernel sources is
in key_handler() (in program.c), where it is used to respond to the VIEW
key.  However, this usage will only happen when no user program is running:

>      case KEY_VIEW:
> // works only if no programs are running.
> if (nb_tasks > NUM_SYSTEM_THREADS)
>   break;

The reason this is important is that mm_free_mem() doesn't check to see
if each block of memory is in use... it just tallies them up:

>//! return the number of bytes of unallocated memory
>int mm_free_mem(void) {
> int free = 0;
> size_t *ptr;
>
>#ifdef CONF_TM
>sem_wait(&mm_semaphore);
>#endif
>
>// Iterate through the free list
>for (ptr = mm_first_free;
>      ptr >= &mm_start;
>      ptr += *(ptr+1) + MM_HEADER_SIZE)
>
free += *(ptr+1);
>
>#ifdef CONF_TM
>sem_post(&mm_semaphore);
>#endif return free*2;
>}

Note the statement executed inside the for loop - there's no test to see
if the block is free.  I wrote a test program to verify the issue.  It's
a bit long, so I posted it at http://mywebpages.comcast.net/yankeejason.
  The fix, also documented on my web page, is to change the inside of
the for loop to read:

if (*ptr==MM_FREE) free += *(ptr+1);

After which the test program performs as expected.

The second caveat is memory fragmentation.  Joseph Woolley has already
documented this issue and a solution previously in this thread.  It
should be noted, however, that calling mm_defrag() prior to checking
mm_free_mem() will only work if no other memory is allocated.  In other
words, you cannot take an initial mm_free_mem() reading, allocate 5
blocks, free 4 blocks, and take another mm_free_mem() reading, with the
intent to account for the extra block, because the extra block may
prevet full defragging.  As long as leak checking is performed after all
known memory is freed, this isn't a concern.  Otherwise, you must ensure
that ALL memory allocated between calls to mm_free_mem() has been
free()ed prior to the mm_defrag() call.

More advanced debugging needs could be addressed by adding another
function to mm.c, called mm_free_mem_dbg().  The code would be identical
to mm_free_mem, except that the contents of the if() statement would be
changed to this:
if (*ptr==MM_FREE) free += *(ptr+1) + MM_HEADER_SIZE;

The return value would include all free memory AND all bytes used for
headers in the free blocks, allowing an apples-to-apples comparison of
free space without a call to mm_defrag(), or in cases where allocated
memory prevents a full defrag.

The final issue I ran into is threading.  Each call to execi() allocates
stack space to the new thread using malloc()... and that means memory
allocated from the free pool.  malloc is also called to allocate space
for other data structures, such as the process descriptor (pdata
structure).  The result is that all threads should be started *prior* to
getting the initial mm_free_mem() value.  In addition, checking for
leaks in one thread can be confused by allocations and frees in other
threads.

Again, a more robust solution for more advanced needs can be found by
further modifying the basic code in mm_free_mem().  A new version,
called mm_used_mem(pid_t pid), can check for pid instead of MM_FREE,
allowing you to see how much memory is allocated to a thread, allowing
you to back other threads' allocations out of the equation.  NOTE:  This
method still won't account for stack space, pdata, etc, so you still
must start all threads before calling mm_free_mem().  This is because
the parent process owns the stack space, etc.

SO now my questions... how much of concern is memory integrity testing?
   Is it worth creating a full set of memory reporting routines (such as
mm_free_mem_dbg() and mm_used_mem(pid) suggested above for inclusion in
the kernel?  I'm of the opinion that its not, although I do think
mm_free_mem() needs to be patched as suggested above to only report
MM_FREE blocks.

Sorry so long winded.
-Jason



Message is in Reply To:
  Re: detecting memory leaks
 
In case anyone attempts to use the mm_defrag() posted previously... you will need the following update to mm_try_join() //! check for free blocks after this one and join them if possible /* \param ptr pointer to size field of current block \return (...) (22 years ago, 13-Jul-02, to lugnet.robotics.rcx.legos)

5 Messages in This Thread:

Entire Thread on One Page:
Nested:  All | Brief | Compact | Dots
Linear:  All | Brief | Compact
    

Custom Search

©2005 LUGNET. All rights reserved. - hosted by steinbruch.info GbR