.st0{fill:#FFFFFF;}

Arduino

Dynamic Memory Allocation: Use and Misuse in Arduino Programming 

 January 11, 2024

By  Peter

Join Our Mailing List

We publish fresh content each week. Read how-to's on Arduino, ESP32, KiCad, Node-RED, drones and more. Listen to interviews. Learn about new tech with our comprehensive reviews. Get discount offers for our courses and books. Interact with our community.

One email per week, no spam, unsubscribe at any time.

Dynamic memory allocation in Arduino might sound like a complex concept, but it’s essentially about managing the memory of your Arduino board efficiently.

At the heart of this are two functions: malloc() and free().

Let’s unravel the functionality of these functions and see how they can be useful (and sometimes problematic).

Understanding malloc() and free()

malloc(), short for “memory allocation”, is used when you need to allocate a specific amount of memory during the runtime of your program. It gives you control over how much memory you use, depending on what your program needs at any given time. Once you’re done with the allocated memory, you use free() to release it back to the system.

Why does this matter?

Arduino boards have limited memory. Using malloc() and free() lets you optimize memory usage, especially when you’re unsure how much memory you will need when writing your program.

When Dynamic Memory Allocation is Useful

Imagine you’re creating a data logger that records temperature readings. The number of readings might vary significantly.

Using malloc(), you can allocate just enough memory to store these readings rather than reserving a large array from the start.

Another scenario could be if you’re working with text data that changes in size, like strings from a sensor or a network. Dynamic memory allocation allows you to adjust the memory used based on the size of the incoming data.

Misuse of Dynamic Memory Allocation

However, dynamic memory allocation is an advanced technique that can cause problems if not used properly. Misusing it can lead to problems like memory leaks and fragmentation. A memory leak happens when you allocate memory using malloc() but forget to free it with free(). Over time, this eats up the memory, leading to crashes or unexpected behaviour.

Fragmentation is another risk. It occurs when you frequently allocate and deallocate memory in small chunks, leaving the memory space fragmented and inefficient. Think of it like trying to fit different-sized books neatly on a shelf. Over time, finding space for new books becomes hard even though there’s technically enough space overall.

A simple example of Dynamic Memory Allocation

Let’s look at an example where we use malloc() and free() to dynamically manage memory in an Arduino Uno R3 project.

In this example, we’ll simulate a situation where you’re reading a variable number of sensor readings and storing them in an array. The array size will depend on how many readings we need, which we’ll determine at runtime.

#include <Arduino.h>

int *readings;  // Pointer for our dynamic array
int numReadings; // Number of readings to store

void setup() {
  Serial.begin(9600);

  // Let's assume we determine the number of readings dynamically
  // For demonstration, we're setting it manually here
  numReadings = 10;

  // Allocate memory for the readings
  readings = (int *)malloc(numReadings * sizeof(int));

  // Check if memory allocation was successful
  if (readings == NULL) {
    Serial.println("Memory allocation failed");
    return;
  }

  // Simulate reading sensor data and store it in the array
  for (int i = 0; i < numReadings; i++) {
    readings[i] = analogRead(A0);  // Replace with actual sensor reading logic
    delay(100);  // Delay for demonstration purposes
  }

  // Print the readings
  for (int i = 0; i < numReadings; i++) {
    Serial.print("Reading ");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(readings[i]);
  }

  // Free the allocated memory when done
  free(readings);
}

void loop() {
  // Your loop code here
}

Here are a few pointers to help you better understand this example code:

  • We’re dynamically allocating an array to store sensor readings using malloc().
  • The size of the array is determined at runtime, showcasing the flexibility of dynamic memory allocation.
  • After using the array, we release the allocated memory using free().
  • We include a check to ensure that the memory allocation was successful. This is crucial in a good practice scenario to avoid undefined behaviour if malloc() fails.

I have also prepared an example code where dynamic memory allocation is used incorrectly. Check this out.

Dynamic Memory allocation done badly

Let’s look at an example where malloc() and free() are used incorrectly in an Arduino sketch. In this scenario, we’ll simulate a common mistake where memory is allocated in a loop without being freed properly, leading to a memory leak.

#include <Arduino.h>

void setup() {
  Serial.begin(9600);
}

void loop() {
  int *data;

  // Allocate memory for an array of 10 integers
  data = (int *)malloc(10 * sizeof(int));

  // Check if memory allocation was successful
  if (data == NULL) {
    Serial.println("Memory allocation failed");
    return;
  }

  // Simulate some operations with the data
  for (int i = 0; i < 10; i++) {
    data[i] = i;
  }

  // Intentionally forgetting to free the allocated memory
  // free(data);

  // Delay for demonstration purposes
  delay(1000);

  // The loop continues, allocating more memory each time without freeing the previous allocation
}

Let’s look at what is going on in this example:

  • Memory is allocated each time the loop() function runs but is never freed. This results in a memory leak, where the Arduino’s limited memory gets used up over time without release.
  • The repeated allocation without deallocation will eventually exhaust the available memory, leading to system instability or crashes.
  • This is a classic example of improper use of dynamic memory allocation, showcasing how forgetting to use free() can cause serious issues in embedded systems like Arduino.

This code is a cautionary example of how mismanagement of dynamic memory can lead to memory leaks, particularly problematic in resource-constrained environments like the Arduino.

The “one thing” to take away

Dynamic memory allocation can be a powerful tool in your Arduino programming arsenal. It gives you flexibility and efficiency in managing memory. However, it requires a thoughtful approach.

Always remember to free up memory when it’s no longer needed, and be cautious about allocating and deallocating memory frequently.


Tags

dynamic memory, free, malloc


You may also like

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

I’m excited to introduce you to the latest and greatest version of KiCad – version 8 (stable release). This article will overview the new features and capabilities added to this popular open-source electronic design automation

Read More
KiCad 8: The new and updated features, a full review

Learning anything worth learning from the ground up is hard. The road to proficiency is filled with roadblocks, distractions, and dead-ends. Everyone learns differently and for different reasons. Some of us learn to advance our

Read More
From struggling to thriving: Understanding the journey from Beginner to Proficient (in programming or anything else)