Skip to main content
tinkerer42
Associate III
August 15, 2022
Solved

Determine heap free space on STM32

  • August 15, 2022
  • 6 replies
  • 15277 views

I'm using an STM32L4 with STM32CubeIDE, bare metal, and using C++ along with Cube's C libraries. The compiler is the GCC/G++ supplied with STM32CubeIDE.

I have some dynamic memory usage in STL containers etc. I'm aware of the recommendation not to use dynamic memory on bare-metal embedded systems, but it is generally used only during initialization, minimizing the complications.

I would like to know how much of the heap I'm using, and found no way to do that. I saw discussions of __heapstats but it doesn't seem to be defined in this toolchain (?).

It doesn't have to be a programmatic way, if there is some internal data structure of newlib or whatever that I can watch while debugging that will suffice.

p.s.

I know the term "free heap space" is not very well defined, because of block sizes and fragmentation, but I suspect that in my case it's going to be one big free block.

any ideas?

This topic has been closed for replies.
Best answer by Semer CHERNI

Hello @tinkerer42​ 

The most generic way to detect stack/heap collisions during run-time would be to by inserting a "known pattern" inside the RAM-memory.

If this memory is completely overwritten then you will know that the heap and stack has collided...

I think there should be some previous ticket where we advised how customer how he can re-write the Reset_Handler to fill the unused RAM with a known pattern.

Have a look at this extension to startup code:

LoopFillZerobss:

ldr r3, = _ebss

cmp r2, r3

bcc FillZerobss

/* ============================ */

/* Fill space between Heap and stack with magic pattern */

ldr r2, =_ebss

mov r4, sp

movs r3, #0xa5a5a5a5 /* The magic pattern */

b LoopFillPattern

FillPattern:

str r3, [r2]

adds r2, r2, #4

LoopFillPattern:

cmp r2, r4

bcc FillPattern

/* Call static constructors */

bl __libc_init_array

Kind regards,

Semer.

6 replies

Tesla DeLorean
Guru
August 15, 2022

Walk the linked list the allocator uses..

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
tinkerer42
Associate III
August 15, 2022

thanks, not pretty but I'll do it if there's no built-in lib to do it for me. I'd like to ask then -

  • what's the name of the data structure?
  • Is it the same structure both for C's malloc() and C++'s new() (or equivalent operations)?

the compiler is the GCC / G++ supplied with STM32CubeIDE, by the way.

Tesla DeLorean
Guru
August 15, 2022

The question looks more expansive now.

I'm using Keil.

__microlib_freelist_initialised

__microlib_freelist

The structure is ahead of the pointer returned by malloc()

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
tinkerer42
Associate III
August 15, 2022

Thanks, can anyone provide a similar answer for STM32CubeIDE's toolchain?

Tesla DeLorean
Guru
August 15, 2022
Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
tinkerer42
Associate III
August 16, 2022

What would I do with looking at the ELF etc? as they are the results of compilation and therefore know nothing about the runtime state of the heap?

S.Ma
Principal
August 15, 2022

Why not union your variables with main global ones if they are exclusied in sequence, saving mallocs logic? (Manual clearing.maybe needed)

Tesla DeLorean
Guru
August 16, 2022

Dynamic allocation has its place, especially allocating buffers and objects at start-up, and where the usage might be configurable, or transitory

Now obviously using it like you would on a desktop, with no regard to leaks, or balance, that's a problem. Using it continuously is also not particularly advisable.

Then again using globals in an excessive and sloppy manner is also something to be avoided.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Semer CHERNI
ST Employee
August 17, 2022

Hello @tinkerer42​ 

The most generic way to detect stack/heap collisions during run-time would be to by inserting a "known pattern" inside the RAM-memory.

If this memory is completely overwritten then you will know that the heap and stack has collided...

I think there should be some previous ticket where we advised how customer how he can re-write the Reset_Handler to fill the unused RAM with a known pattern.

Have a look at this extension to startup code:

LoopFillZerobss:

ldr r3, = _ebss

cmp r2, r3

bcc FillZerobss

/* ============================ */

/* Fill space between Heap and stack with magic pattern */

ldr r2, =_ebss

mov r4, sp

movs r3, #0xa5a5a5a5 /* The magic pattern */

b LoopFillPattern

FillPattern:

str r3, [r2]

adds r2, r2, #4

LoopFillPattern:

cmp r2, r4

bcc FillPattern

/* Call static constructors */

bl __libc_init_array

Kind regards,

Semer.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Tesla DeLorean
Guru
August 17, 2022

I don't recall stack collision, or stack size, being the question. This would be a good way of determining the low water mark of the stack, and high water mark on the heap within that same space. Not very enlightening on the current state of heap or stack, or determine used/unused sections of the heap. The heaps here are pretty simplistic linked lists.

What if the stack and heap are in entirely different memory regions? What if _sbrk() worked properly? Having it assume it's in the same memory region, and that the current base of the stack is a safe bounding condition, really not inspiring confidence at this end.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
tinkerer42
Associate III
August 17, 2022

that's probably the most robust solution, I'll try that.

Thanks!