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=malloc(512);
}

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
_______________________________________________
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users

Reply via email to