2020-09-25 08:31 AM
Hello,
I'm porting a C++ application to a STM32 device. The application itself is running, but I'm observing heap memory growing into the stack and firing an exception after a while. Running the application on Windows within Visual Studio shows the same behaviour regarding used memory going only up, but without crashing. This might be because there are GB of RAM instead of kB ;)
But I doubt that the application has memory leaks, I think that Windows is kidding me. The application is originally written on a Mac device. I'm in contact with the author and he couldn't see this behaviour on his setup and also never had crashes.
So, I assume I'm missing some compiler settings or something like that and I want to investigate the issue. I saw some articles regarding C++ on embedded devices and they recommend to overwrite the new and delete operator to use malloc() and free(). If I'd do this, I would also output a message how many memory is requested and freed. But I want to know the default implementation of the new and delete operators to check how they work. Where can I find those informations?
Thank you.
Regards
2020-09-25 08:56 AM
The default operator new is basically a wrapper around malloc and uses the same heap.
If this app needs amount or RAM not available on STM32, or leaks memory - game is over.
Does that guy test his app on a similar ARM 32-bit? Yes, WIndows or OSX has GBs of RAM and it matters.
If you use threads (some RTOS) - the runtime library provided with CubeIDE does not support threads. You'll need to find a workaround.
-- pa
2020-09-25 09:12 AM
As far as I know, new / delete uses newlib's native _malloc_r() / _free_r() functions. Who themselves use the _sbrk() (or _sbrk_r()) function in syscalls.c
The redefinition of the _malloc_r() / _free_r() functions by the user allows you to manage the memory allocation yourself (the presence of your functions prevents the linker to link the newlib functions).
if your _malloc_r() / _free_r() are not thread safe, you have to implement __malloc_lock() and __malloc_unlock()
https://tty.uchuujin.de/2016/04/stm32-from-scratch-heap/
https://stackoverflow.com/questions/19258847/stm32-c-operator-new-coide
Some infos about malloc and newlib:
2020-09-25 09:54 AM
@Pavel A.
No, he can't test it on ARM devices. There was never an embedded bare-metal target in scope when whe wrote this application. And the application doesn't use threads.
@Nikita91
Thank you for those links, I'll go through them. If new and delete really use malloc() and free() and nothing else, I think overwriting them with additional output capabilities shouldn't be a problem. I wrote a _sbrk() implementation at the beginning of the project, as well as some other functions needed by library/project. I assume(!) this _sbrk() implementation is working correctly. At least it looks okay for me, but I'm a beginner with newlib internals.
So, both C and C++ use newlib in general, is this true?
Regards
2020-09-25 10:21 AM
You can instrument _sbrk() to track the count and size of malloc. Not with printf, but with SWO or direct output to an UART.
Programming Windows or microcontrollers are not the same job...
2020-09-25 10:35 AM
Yes, should be no problem with SWO. I know that this is not the same :) I've more experience with programming MCUs. Sometimes, when I see source code for desktop OS I think 'what a waste of memory'. I learned MCU programming on 8052s with assembler, so memory was always rare...
2020-09-26 04:43 AM
Hmm... seems the SWO output is disturbed. Not much, but some packets are lost. Maybe using a delay will help.
Back to the original question, is there any source which shows how the default operations are implemented?
Regards
2020-09-26 05:31 AM
You have to dig in newlib source code.
The newlib vesion distributed with CubeIDE is 3.0.0:
ftp://sourceware.org/pub/newlib/newlib-3.0.0.tar.gz (81ec873108b8593c586f91ca65963952)
The newlib vesion distributed with Atollic 9.3.0 is 2.5.0
ftp://sourceware.org/pub/newlib/newlib-2.5.0.tar.gz
2020-09-28 08:34 AM
Hi Nikita,
thank you for those links, I'll go through them and try to figure out how the memory management is working. Currently it seems that the heap is only growing upward, but never goes down. This measurement was taken within _sbrk() function, output was written into a character array by snprintf() - for this function I assume(!) that it won't use dynamic memory. Even if this is not true, I'd assume that I should see a negative increment within _sbrk() at least sometimes.
Regards
2020-09-29 01:52 AM
For an embedded device, carefully consider the use of dynamically allocated memory. During setup, you can do it. But using it during runtime probably will hit a memory limit at some point in time and that will be hard to debug.