freeMemory() - alternative in portenta

Is there a way to find out the free memory of a running system.

I tried

#include <MemoryFree.h>

i = freeMemory();

But the function, nor the header library exist.

Is there some other portenta option. I would like to periodically print the free memory, just to make sure I do not have any memory leak issues

Thanks

Could you check if the "MBED_HEAP_STATS_ENABLED" and "MBED_STACK_STATS_ENABLED" are defined and are set to 1 ?
Then you can request the memory usage from Mbed: https://os.mbed.com/docs/mbed-os/v6.15/apis/runtime-memory-statistics.html

Thanks - I tried 2 ways, and that one seems to work

          char   stackVariable;
          void   *heap;
          unsigned long l1, l2;
          unsigned long result;
          mbed_stats_heap_t heap_stats;

          heap  = malloc(4);
          l1 = (unsigned long)&stackVariable;
          l2 = (unsigned long)heap;
          result  = l1 - l2;
          free(heap);
   
          Serial.print("freemem = ");
          Serial.println(result, DEC);

          Serial.println("Starting heap stats example");
          mbed_stats_heap_get(&heap_stats);
          Serial.print("Start; Current heap: ");
          Serial.print(heap_stats.current_size, DEC);
          Serial.print("  Start; Max heap size: ");
          Serial.println(heap_stats.max_size, DEC);
freemem = 5005
Starting heap stats example
Start; Current heap: 61807  Start; Max heap size: 331341
freemem = 5005
Starting heap stats example
Start; Current heap: 61807  Start; Max heap size: 331341

The freemem way seems to not give a correct answer, l1-l2 gives a 4 gigabyte number, and l2-l1 goves 5005 (which I know I have more RAM than that.

Heaps gives current 618707 and max 331341.

I do not use malloc and free myself, and my subroutines do not use that much RAM, so presumably the mbed startup must use some RAM taht resulted in the large Max size?

After running through a lap of my software, I get the same numbers - so that is promising.

This should do something similar:

size_t* ptr = new(size_t);
size_t result = (size_t)&ptr - (size_t)ptr;
delete(ptr);

Sorry, what do you want to accomplish with this local variable?
If you substract from the address of a local variable (&ptr) the address assigned by malloc() - you can get any huge value.
Example:

  • stack is on region 0x20000000 (DTCM RAM)
  • malloc uses SRAM, e.g. 0x30000000
    0x20000000 - 0x30000000 gives you a really huge value: 0xF0000000 (all the other space as "wrap around".
    This is not what you want to know.

Could you use the info from linker_script.ld, e.g.:

__HeapLimit

Not tried, but something like:

extern unsigned long __HeapLimit;
int *ptr = new(int);
size_t available = (size_t)__HeapLimit - (size_t)ptr;
free(ptr);

Actually, even this will FAIL:
what if your memory is already fragmented, by so much use of malloc()? There is no guarantee that the segments on heap memory are linear. You can find a free space, here for just 4 byte variable anywhere in heap memory. But the tail is allocated. This math operation would give you a wrong result.

Actually: using malloc nobody can really tell you how much is free. It can happen that the memory is so fragmented after a while, might have in total still 2 KB free, but these 2 KB are spread over many different segments. You would not be able to allocate 2 KB as one single chunk.

The correct question to ask malloc is actually: what is the largest block of memory I could still allocate (not how much is free, in total - not the same info)?

You have to check the return when calling malloc(). If you see you cannot allocate anymore 2 KB - you hit the case that memory is meanwhile too fragmented. It does not mean, 2 KB are just left: you can have still N times 1 KB blocks still available, just 2 KB as one chunk is not possible anymore.

Personally, I try to avoid to use malloc. RTOS provides functions for MemoryPool which are much safer (in terms to avoid memory fragmentation).
Or I use my own MemPool implementation: it is based on fix size chunks. Memory is managed in these chunks. There is always a guarantee that a chunk is still available if not really all chunks are allocated. And the chunk size correlates with the most often used size, e.g. for dynamic buffers, e.g. needing most of the time as 4K.
In my own implementation of MemPool I can track the use: how much is free, what was the peak (watermark) on use, how much MemPool segments are still in use...?

Here a simple MemPool implementation (I use in all my projects):
MEM_Pool.h (2.2 KB)
MEM_Pool.c (4.4 KB)

In my application, there is a malloc that is called for each attached device at the start of the code - once - and that memory is never released.

Then there is a second malloc that is called for a graphics routine - also called just once, and the value placed in a static variable - so that is never release either.

I think if it is used like that, or if a free is called for the last malloc called, then there should not be a problem . However if the free the last malloc strategy is used, I think it has to be well debugged to make sure that is what happens.

That's true:
If you allocate just once for all devices their memory and you never "free" it - there is no issue with fragmentation. And we can assume it is allocated in a linear way (but who knows? It depends how malloc() is implemented, e.g. large buffers use the upper part, small buffers the lower part of entire heap memory).

But in this case, you can also allocate a simple variable (after all done), check their address (how much higher it is in comparison with very first address from malloc).

But how do you know how much size is configured for heap (for malloc())?

  • it can come from linker_script.ld - see there:
__HEAP_SIZE  = 0x4000;

.heap (NOLOAD):
    {
        __end__ = .;
        PROVIDE(end = .);
        *(.heap*)
        . = ORIGIN(DTCMRAM) + (LENGTH(DTCMRAM)-__STACK_SIZE) - __HEAP_SIZE;
        __HeapLimit = .;
    } >DTCMRAM
  • or: the heap comes from RTOS: I see in CMSIS RTOS code that the memory for threads, memory pools etc. comes from a global variable, not via malloc().
    How do you know for sure what the heap size for malloc() is?
    (if via linker_script: the __HEAP_SIZE - which can be used like a global variable - might tell you, but if RTOS and using a macro definition there for the size of a global memory array?)

BTW: if the linker_script.ld defines __HEAP_SIZE - it is not the real complete memory you can use! malloc() creates a management structure on the same memory (at the start of the heap memory). The total size is a bit less (minus the management structure size itself).

As long as all malloc() is OK - why do you want to figure out how much is still left?

Before you allocate the memories for your devices - you could try to figure out what the heap size is: try to allocate a buffer with a variable size: start very large, e.g. 32 KB. If it fails, step down and try again with the next 1/2, here 16 KB - until you see you get it now (maybe you get it for 4K error free). Free the memory again and take this result as the maximum heap size possible (do the size in steps like in a "binary search": from largest to smaller sizes to find where the boundary is).

Now you allocate all your buffers you need. Take the last address you have allocated plus the size of this buffer (as the end address of this buffer) and compare it against the very first buffer via malloc(). The difference is the allocated size. The maximum size you got in the step before.
Now, you would know how much is left (assuming still: all is unfragmented and still linear in terms of memory regions).

BTW:
to use malloc() and never to free is not the "intention" of malloc(). It would be identical to define all the memories as regular buffers. In such a case, that the memory is never de-allocated (never freed) - it is easier to understand if you give any device their memory they need via a definition.
And you can gain memory if you make the heap smaller or even: get completely rid of heap (set to 0) if malloc() is never used (this is what I do: I never use malloc() and set my heap to 0).

malloc() makes only sense if you "share" memories between different devices in a "dynamic" way: for instance: I need network buffers when I get a HTTP request. But if no network or the request has been done - I want to use the "same" memory for other devices, e.g. send a large SPI transaction.

If nothing is dynamic - I would not use malloc(). (it is not needed and creates just overhead).
You can also reuse a buffer by yourself: if you know something is exclusive, e.g. just a HTTPD request can be there or a command via UART for the SPI - but never both at the same time - I can use the same memory buffer, defined on source code, without to use malloc() (with all the risks and overhead). Just handle it like a "scratch RAM".

Thanks for the explanation. Basically, I wanted to make sure there is no memory leak from any of the libraries and other code. The only malloc I used that I freed, was the one to determine the address location (and that is only during debugging - it will be commented out in the final version).

I am not using malloc (that I subsequently free - and the only malloc is for the SDRAM), nor recursion, only a handful of global classes and variables, and everything else is on the stack. I should be OK, but mbed and all the portenta libraries are new, so I think it would be good to check nothing out of the ordinary is happening.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.