I've seen this and this topics but I don't know if in my c++ / IDE version the problem is already solved because I don't know how to check my runtime C library version.
Any ideia on how to solve this problem?
My IDE version is the 1.8.15 and my board an arduino nano 33 IOT
The freeMemory library reports the distance between the top of the stack and __brkval . Malloc is not necessarily going to lower __brkval immediately after you deallocate something at the top of the heap, it keeps some recently deallocated memory ready for when the next allocation request comes in.
As a side note, you should not use naked new and delete, these are meant for low-level code only.
If you need dynamic memory allocation, use standard library containers such as std::vector, or if you need just one element, smart pointers such as std::unique_ptr:
#include <memory>
void setup() {
Serial.print("Free Memory: ");
Serial.println(freeMemory());
{
// auto obj = std::make_unique<CustomObj>(); // C++14
auto obj = std::unique_ptr<CustomObj>(new CustomObj); // C++11 :(
Serial.print("Free Memory: ");
Serial.println(freeMemory());
} // obj is automatically cleaned up here
Serial.print("Free Memory: ");
Serial.println(freeMemory());
}
void loop() {}
please remember, unlike other programming, Arduino has no underlying operating system. So there is nothing in the background reserving or releasing memory. Since your sketch is the only process running on your arduino. There is no purpose in releasing memory.
memory is reserved ahead of time with the variable declarations in your sketch.
The thing is... I need to create dynamic variables based on the list of networks available and add them to a menu. Currently I'm using this library to create the menus.
The way I'm doing it is Using the wifininna library to search for networks and on a for loop instantiate new menus with the new keyboard and adding them to my menu.
After I'm done with it, I iterate over the menu components and delete them with the delete keyword. I tried smart points but the library does not support them so I would require me to change it ir order to make it work.
One option would be to have a global shared pointer to hold all instances until I'm done with them but I was looking for a cleaner solution.
The code is something like this. The on_wifi_networks_selected is a callback function that is called when the menu for searching networks is selected and the DynamicMenu is a custom Menu that extends the library Menu so I can override the reset method and use delete to reset the components.
void on_wifi_networks_selected(MenuComponent* p_menu_component) {
int num_ssid = WiFi.scanNetworks();
...
for(int i=0; i<num_ssid; i++) {
DynamicMenu* network = new DynamicMenu(WiFi.SSID(i));
KeyboardMenuItem* keyboard = new KeyboardMenuItem("Keyboard", &on_wifi_password_inserted);
BackMenuItem* exit_keyboard = new BackMenuItem("Exit", nullptr, &ms);
network->add_item(keyboard);
network->add_item(exit_keyboard);
wifi_menu->add_menu(network);
}
.....
}
Any ideas on how to do this in another way?
P.S: regarding the memory, I made a test and it eventually crash so I guess the memory is never being free or re-used.
Unless you have various and competing needs for memory based on unknowable circumstances, the usual technique in this case would be to plan.
Plan for a (the) maximum number of networks that your system will handle, declare static memory memory sufficient for that number and program contingencies for reaching the limit at run time.
Which by design shouldn’t happen..but it would be good to know when it did and have a plan B.
Even if you did have various and competing needs for memory, in a small system it is better to avoid dynamic allocation through use of common and well understood algorithms and data structures.
This should work if you never forget to deallocate anything, never overwrite owning pointers, etc. but it's error prone.
I'd suggest using a separate std::vector for storage if you need dynamic memory allocation, or just an array if you know the maximum capacity you need.
You'll still have to watch out for dangling pointers, of course, but this at least solves your memory management problems.
Is this for the simple CustomObj example you posted first, or for your actual code?
Because you need some way to manage the memory, keep track of which blocks are free and which blocks are in use.
The limited RAM is shared between the heap and the stack, you don't want the heap to grow unbounded, running into the stack. __brkval is this separation between heap and stack, if you deallocate things from the heap, you want to decrease __brkval so the memory can later be reused by the stack, e.g. for recursive or deeply nested function calls or functions with large stack frames.
The code you posted just runs once, so it shouldn't crash.
This output is expected, like I said, delete/free doesn't decrease __brkval immediately, it keeps some blocks ready in a free list for the next allocation.
Try moving the allocations to the loop and see if it crashes for the simple example.
If it does, then there's a fatal flaw in Arduino's malloc implementation.
If it doesn't, then that's an indication that you have an actual memory leak in your more complicated code. This is usually the most likely cause.
You might also see a crash from memory fragmentation, but since you have 32KiB of RAM and you're not doing anything too crazy with dynamic memory (at least in the code you shared), I think an actual leak is more likely than just fragmentation.
So I tried in the main loop and the memory doesn't even move... It stayed stable. So probably you're are right and the leak is on another place.
Looking deeper into the menu library I was using I found this method:
void Menu::add_component(MenuComponent* p_component) {
// Resize menu component list, keeping existing items.
// If it fails, there the item is not added and the function returns.
_menu_components = (MenuComponent**) realloc(_menu_components,
(_num_components + 1)
* sizeof(MenuComponent*));
if (_menu_components == nullptr)
return;
_menu_components[_num_components] = p_component;
if (_num_components == 0) {
_p_current_component = p_component;
_p_current_component->set_current();
}
_num_components++;
}
I'm not sure if that realloc method may be causing the problem but I guess is worth a shot trying to modify the library to use a std::vector and see if the problem persists.
It's probably not the bug you're seeing, but if realloc fails, it returns null and it doesn't free the old memory.
So if realloc fails, the library leaks, and Menu::_menu_components is now null, possibly causing issues elsewhere.
Growing by one element only is not great for fragmentation either, you usually want to grow by more than that to limit the number of allocations.
Given these issues, I'd say there's a good chance that the author made other mistakes as well and might have written other memory leaks.
Replacing things like _menu_components by an std::vector would be a good start.