I am trying to better understand memory allocation in my MEGA 2560 project.
In my complex smart car project I am trying to change some member variables into global variables. I think this should require the same amount of memory, either way, but what I am seeing is that each global variable requires 57 bytes of SRAM. There are 15 of these variables and I don’t want to lose 855 bytes of SRAM.
I created this small project to try to isolate the problem. Unfortunately, this does not show the problem I am really trying to solve, but hopefully I can get clues by analyzing the difference between the two results.
The code below can be run two ways, with #define nested true or false. I have run this in the standard Arduino IDE and also in the Eclipse/Sloeber environment, which is what I use most of the time. The output is the same either way. The Arduino IDE reports 168 or 166 bytes more flash usage.
There are lots of differences between the two primary conditions that I am trying to explain. Why does the heap usage and heap size change the way it does? The code I use to obtain the heap and stack size is included. It is based on code that was posted here. I have fixed a few bugs in the heap code, but there may be better ways to get this information (more accurately).
Thanks for helping me understand the details of what is happening here.
-Christopher
RESULTS
EXAMPLE 1
Arduino IDE:
avrdude: 5232 bytes of flash verified
Sketch uses 5232 bytes (2%) of program storage space. Maximum is 253952 bytes.
Global variables use 540 bytes (6%) of dynamic memory, leaving 7652 bytes for local variables. Maximum is 8192 bytes.
Eclipse/Sloeber: avrdude: 5064 bytes of flash verified
Memory study
Nested: 1
Heap before allocation
Heap Usage: 7649 / 15276 Stack Size: 19 Free RAM: 7627 [Stack 8700:8681 Heap 8703:1054]
Heap after allocation
Heap Usage: 7641 / 15260 Stack Size: 19 Free RAM: 7619 [Stack 8700:8681 Heap 8703:1062]
Inner value: 1
Sizeof Inner: 2 == 2
Sizeof Wrapper: 2 == 2
Heap in loop
Heap Usage: 7641 / 15260 Stack Size: 19 Free RAM: 7619 [Stack 8700:8681 Heap 8703:1062]
EXAMPLE 2
Arduino IDE:
avrdude: 5212 bytes of flash verified
Sketch uses 5212 bytes (2%) of program storage space. Maximum is 253952 bytes.
Global variables use 540 bytes (6%) of dynamic memory, leaving 7652 bytes for local variables. Maximum is 8192 bytes.
Eclipse/Sloeber: avrdude: 5046 bytes of flash verified
Memory study
Nested: 0
Heap before allocation
Heap Usage: 7649 / 15276 Stack Size: 19 Free RAM: 7627 [Stack 8700:8681 Heap 8703:1054]
Heap after allocation
Heap Usage: 7645 / 15268 Stack Size: 19 Free RAM: 7623 [Stack 8700:8681 Heap 8703:1058]
Inner value: 2
Sizeof Inner: 2 == 2
Sizeof Wrapper: 1 == 1
Heap in loop
Heap Usage: 7645 / 15268 Stack Size: 19 Free RAM: 7623 [Stack 8700:8681 Heap 8703:1058]
/*
* mem.ino
* Memory allocation study.
* Christopher Eliot
* cre@empiremaster.com
*/
#include <Arduino.h>
#include "heap.hpp"
#define BUF_SIZE (256)
char buffer[BUF_SIZE];
#define nested false
class Inner
{
public:
Inner (int value) :
value(value)
{
}
int value;
};
#if ! nested
Inner *inner;
#endif
class Wrapper
{
public:
#if nested
Wrapper () :
inner(new Inner(1))
{
}
Inner *inner;
#endif
int get_inner_value ()
{
return inner->value;
}
size_t get_inner_size ()
{
return sizeof(*inner);
}
};
Wrapper *wrapper;
void setup ()
{
Serial.begin(115200);
Serial.println(F("Memory study"));
Serial.print(F("Nested: "));
Serial.println(nested);
Serial.println(F("Heap before allocation"));
get_heap_state(buffer, BUF_SIZE);
Serial.println(buffer);
#if ! nested
inner = new Inner(2);
#endif
wrapper = new Wrapper();
Serial.println(F("Heap after allocation"));
get_heap_state(buffer, BUF_SIZE);
Serial.println(buffer);
Serial.print(F("Inner value: "));
Serial.println(wrapper->get_inner_value());
Serial.print(F("Sizeof Inner: "));
Serial.print(wrapper->get_inner_size());
Serial.print(F(" == ")); // Should match
Serial.println(sizeof(Inner));
Serial.print(F("Sizeof Wrapper: "));
Serial.print(sizeof(*wrapper));
Serial.print(F(" == ")); // Should match
Serial.println(sizeof(Wrapper));
}
void loop ()
{
Serial.println(F("Heap in loop"));
get_heap_state(buffer, BUF_SIZE);
Serial.println(buffer);
delay(50000);
}
/*
* Heap.hpp
*
* Created on: Jan 10, 2023
* Author: cre
*
* Based on: https://forum.arduino.cc/t/getting-heap-size-stack-size-and-free-ram-from-due/678195
*/
#pragma once
void get_heap_state (char *buffer, size_t size);
unsigned long get_free_ram ();
unsigned long get_heap_address ();
/*
* Heap.cpp
*
* Created on: Jan 10, 2023
* Author: cre
*/
#include <Arduino.h>
#include "Heap.hpp"
static const unsigned long initial_stack_address = SP;
void get_heap_state (char *buffer, size_t size)
{
const unsigned long heap_address = get_heap_address();
const unsigned long heap_size = RAMEND - heap_address;
const long stack_size = initial_stack_address - SP;
const unsigned long free_ram = get_free_ram();
const unsigned long sp = SP;
const unsigned long ramend = RAMEND;
snprintf(buffer, size, "Heap Usage: %lu / %lu Stack Size: %lu Free RAM: %lu [Stack %lu:%lu Heap %lu:%lu]",
heap_size, heap_size + free_ram, stack_size, free_ram, initial_stack_address, sp, ramend, heap_address);
}
unsigned long get_free_ram ()
{
char *const heap_var = (char*) malloc(sizeof(char));
const unsigned long heap_address = (unsigned long) heap_var;
free(heap_var);
return SP - heap_address;
}
unsigned long get_heap_address ()
{
char *const heap_var = (char*) malloc(sizeof(char));
const unsigned long heap_address = (unsigned long) heap_var;
free(heap_var);
return heap_address;
}