lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] How to release all memory to track leaks


From: Trampas Stern
Subject: Re: [lwip-users] How to release all memory to track leaks
Date: Fri, 4 Jun 2021 07:43:14 -0400

In C there is a _sbrk(int incr) function.  This function is called when memory allocation or deallocation happens.  
The newlib has their own version of this function, however via linker with the --specs=nosys.spec you can disable the default version and add your own. 

You can google sbrk for more information.....

What I do is implement a break point in the function to see who is allocating memory. I also keep track of the memory allocation as the program runs. 

What I have found is that newlib memory allocation does not always free memory and it also allocates memory if you are using floating point printf().  What happens is newlib has it's own internal memory management system.  For example if you malloc(4) newlib might actually request a block of more than 4 bytes then when you free those 4 bytes newlib might not actually release those bytes and instead mark the block as free internally and reuse it for another malloc(). 

What I do in my programs is implement a serial port command line interface using a debug uart. Then I have a memory command where I print out the stack and heap usage. I can also monitor the stack and heap usage as my program runs to help handle stack and heap overflow more gracefully if needed. I track maximum heap used as well as current heap usage.

I have found that libraries like newlib standard C library will often malloc memory.  This is highly dependent on the functions you use. For example if I recall correctly when you enabled floating point on newlib it will allocate memory when you do a floating point printf().  To avoid this and issues with reentrant on printf()/sprintf() I just implemented my own version.  Every line of code in the project becomes your problem, even standard C library calls. 

As far as releasing all memory for lwip, I find this to be not needed. The most important thing is to know what memory is being used and that it is not growing. For example in C you could do this:

uint8_t data[512]; 
void main(){}

This creates room in RAM for 512 bytes of data that is never released.  However this does the same thing:

uint8_t *data;
void main(){
data="">
}

That is both programs now need 512 bytes of RAM which is never released, the only difference is one is in heap while the other is in the static allocation (bss) section of RAM.   Hence malloc is not evil as many people have said, rather it is a tool you have to know how to use correctly. 
I will say that 99% of the time the code I see that uses malloc() is evil, so there exists a strong correlation to bad code and malloc, but it is not memory allocation's (malloc) fault.  It is always the programmer not understanding what they are doing in the code. 

Note I monitor stack and heap usage, not just for my code, but also for the next guy.  For example projects live long after I am gone, so if the next programmer inserts code that overflows stack or heap it is good that the monitoring catches the error and lets them know before they release code to production, i.e. defensive coding techniques. 

My sbrk function is below, but depends on the linker variables __HeapBase, and __HeapLimit to work.  Note I often add a macro,  HALT_IF_DEBUGGING(), which will insert a breakpoint into the code when a debugger is attached to help track down which functions are doing memory allocations.  

Thanks
Trampas


extern uint32_t __HeapBase;
extern uint32_t __HeapLimit;
uint32_t getHeapUsed(void);
uint32_t getHeapSize(void);
int32_t getLastMalloc(void);

uint32_t heapUsed=0;
int32_t lastMalloc=0;
uint32_t getHeapUsed(void)
{
return heapUsed;
}

uint32_t getHeapSize(void)
{
return (uint32_t)&__HeapLimit-(uint32_t)&__HeapBase;
}

int32_t getLastMalloc(void)
{
return lastMalloc;

}


static unsigned char *heap = (unsigned char *)&__HeapBase;
static unsigned char *max_heap = (unsigned char *)&__HeapBase;

uint32_t getMaxHeapUsed(void)
{
if (max_heap == NULL)
{
return 0;
}
return (uint32_t)max_heap - (uint32_t)&__HeapBase;
}

uint8_t *getHeapPointer(void)
{

return heap;
}
extern caddr_t _sbrk(int incr)
{

unsigned char *prev_heap;

prev_heap = heap;

heap += incr;

if (heap > max_heap)
{
max_heap=heap;
}
lastMalloc = incr;
heapUsed = (uint32_t) heap - (uint32_t) ((unsigned char *) &__HeapBase);

//HALT_IF_DEBUGGING();//if you hit this something allocated memory, which maybe you do not want...

//for (;;) { }

return (caddr_t) prev_heap;
}

On Fri, Jun 4, 2021 at 6:14 AM R. Diez via lwip-users <lwip-users@nongnu.org> wrote:
Hi all:

I have a bare-metal (Newlib, no threads) firmware that uses lwIP and its httpd server to provide a simple web interface.

The firmware is actually quite complex in other areas. I am trying to identify and track down memory leaks, so I implemented a "shutdown" command in the debug console that releases all resources and checks the remaining allocated bytes with mallinfo().

I suspect some of the remaining memory "leaks" belong to lwIP and/or its httpd server, because they only come up after having downloaded the web page once. They are probably not real leaks, because memory usage does not grow over time.

It is hard to say, because I have not figured out yet how to track memory allocations in an embedded Newlib firmware like this.

In any case, I would like lwIP to release all memory on shutdown, in order to locate any memory leaks in other parts. The trouble is, there are routines like lwip_init() and httpd_init(), but no xxx_terminate() counterparts.

I tried removing all interfaces with netif_remove(), but that is probably not enough.

Is there some trick I could use? For example, something like ticking all state machines again after all interfaces have been removed could possibly trigger a complete memory release all over the place.

Thanks in advance,
  rdiez

_______________________________________________
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users

reply via email to

[Prev in Thread] Current Thread [Next in Thread]