user52602: I have a Arduino sketch I made and I have run out of dynamic memory on my Arduino  Nano. How could I possibly reduce the amount of memory the program takes? (I'm not that good at this stuff)
P.S: The code is here:

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const int chipSelect = 4;

#define OLED_RESET 5
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Fix Height");
#endif


/********************************************/

#define CHARWIDTH           5
#define CHARHEIGHT          8
#define AXISWIDTH           (2 + 1)                
#define VISIBLEVALUEPIXELS  (128 - AXISWIDTH)         
#define NUMVALUES           (2 * VISIBLEVALUEPIXELS) 

#define TRIGGER_ENABLE_PIN       2  
#define SCREEN_UPDATE_ENABLE_PIN 3  

byte values[NUMVALUES];        
int pos = 0;                     
int count = 0;                 
unsigned long readStartTime = 0; 
int sampleRate = 1;              

void displayln(const char* format, ...)
{
  char buffer[32];

  va_list args;
  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);

  int len = strlen(buffer);
  for (uint8_t i = 0; i < len; i++) {
    display.write(buffer[i]);
  }
}

// Draws the graph ticks for the vertical axis
void drawAxis()
{  
  // graph ticks
  for (int x = 0; x < 2; x++) {
    display.drawPixel(x,  0, WHITE);
    display.drawPixel(x, 13, WHITE);
    display.drawPixel(x, 26, WHITE);
    display.drawPixel(x, 38, WHITE);
    display.drawPixel(x, 50, WHITE);
    display.drawPixel(x, 63, WHITE);  
  }
}

// Draws the sampled values
void drawValues()
{
  int start = 0;

  if ( digitalRead(TRIGGER_ENABLE_PIN) ) {
    // Find the first occurence of zero
    for (int i = 0; i < NUMVALUES; i++) {
      if ( values[i] == 0 ) {
        // Now find the next value that is not zero
        for (; i < NUMVALUES; i++) {
          if ( values[i] != 0 ) {
            start = i;
            break;
          }
        }
        break;
      }
    }    
    // If the trigger point is not within half of our values, we will 
    // not have enough sample points to show the wave correctly
    if ( start >= VISIBLEVALUEPIXELS )
      return;
  }

  for (int i = 0; i < VISIBLEVALUEPIXELS; i++) {
    display.drawPixel(i + AXISWIDTH, 63 - (values[i + start]), WHITE);
  }
}

// Shows the time taken to sample the values shown on screen
void drawFrameTime(unsigned long us)
{
  display.setCursor(9 * CHARWIDTH, 7 * CHARHEIGHT - 2); // almost at bottom, approximately centered
  displayln("%ld us", us);
}

/********************************************/

void setup() {

  // Set up the display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);

  pinMode(TRIGGER_ENABLE_PIN, INPUT);
  pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT);
    // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("init start");


  if (!SD.begin(chipSelect)) {
    Serial.println("fail");
    // don't do anything more:
    while (1);
  }
  Serial.println("init ok");
}

/********************************************/

void loop() {

  // If a sampling run is about to start, record the start time
  if ( pos == 0 )
    readStartTime = micros();

  // If this iteration is one we want a sample for, take the sample
  if ( (++count) % sampleRate == 0 )
    values[pos++] = analogRead(0) >> 4; // shifting right by 4 efficiently maps 0-1023 range to 0-63

  // If we have filled the sample buffer, display the results on screen
  if ( pos >= NUMVALUES ) {
    // Measure how long the run took
    unsigned long totalSampleTime = (micros() - readStartTime) / 2;     // Divide by 2 because we are taking twice as many samples as are shown on the screen

    if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) {
      // Display the data on screen   
      display.clearDisplay();
      drawAxis();
      drawValues();
      drawFrameTime(totalSampleTime);
      display.display();
    }

    // Reset values for the next sampling run
    pos = 0;
    count = 0;
  }
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
      dataString += ",";
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}


user33226: Few things to consider :

Each variable in your program take memory, try to use the smallest datatype ( don't use a float if you need an int for example).
Eliminate strings 
Reduce the usage of array
Reduce your code size by using function for redudant task
Avoid using digital and analog red/write. Use port manipulation instead (link here)
Modify library to remove unused code inside 
Use ICSP programmer instead of serial bootloader 
Simplify your code for reducing its size. 

Or simply ...
Use another board such as STM32 ou bigger ATmega chip with more RAM and bigger ROM size ...  

52602: <p>I have a Arduino sketch I made and I have run out of dynamic memory on my Arduino  Nano. How could I possibly reduce the amount of memory the program takes? (I'm not that good at this stuff)</p>

<p>P.S: The code is here:
</p>

<pre class="lang-cpp prettyprint-override"><code>#include &lt;SPI.h&gt;
#include &lt;SD.h&gt;
#include &lt;Wire.h&gt;
#include &lt;Adafruit_GFX.h&gt;
#include &lt;Adafruit_SSD1306.h&gt;

const int chipSelect = 4;

#define OLED_RESET 5
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Fix Height");
#endif


/********************************************/

#define CHARWIDTH           5
#define CHARHEIGHT          8
#define AXISWIDTH           (2 + 1)                
#define VISIBLEVALUEPIXELS  (128 - AXISWIDTH)         
#define NUMVALUES           (2 * VISIBLEVALUEPIXELS) 

#define TRIGGER_ENABLE_PIN       2  
#define SCREEN_UPDATE_ENABLE_PIN 3  

byte values[NUMVALUES];        
int pos = 0;                     
int count = 0;                 
unsigned long readStartTime = 0; 
int sampleRate = 1;              

void displayln(const char* format, ...)
{
  char buffer[32];

  va_list args;
  va_start(args, format);
  vsprintf(buffer, format, args);
  va_end(args);

  int len = strlen(buffer);
  for (uint8_t i = 0; i &lt; len; i++) {
    display.write(buffer[i]);
  }
}

// Draws the graph ticks for the vertical axis
void drawAxis()
{  
  // graph ticks
  for (int x = 0; x &lt; 2; x++) {
    display.drawPixel(x,  0, WHITE);
    display.drawPixel(x, 13, WHITE);
    display.drawPixel(x, 26, WHITE);
    display.drawPixel(x, 38, WHITE);
    display.drawPixel(x, 50, WHITE);
    display.drawPixel(x, 63, WHITE);  
  }
}

// Draws the sampled values
void drawValues()
{
  int start = 0;

  if ( digitalRead(TRIGGER_ENABLE_PIN) ) {
    // Find the first occurence of zero
    for (int i = 0; i &lt; NUMVALUES; i++) {
      if ( values[i] == 0 ) {
        // Now find the next value that is not zero
        for (; i &lt; NUMVALUES; i++) {
          if ( values[i] != 0 ) {
            start = i;
            break;
          }
        }
        break;
      }
    }    
    // If the trigger point is not within half of our values, we will 
    // not have enough sample points to show the wave correctly
    if ( start &gt;= VISIBLEVALUEPIXELS )
      return;
  }

  for (int i = 0; i &lt; VISIBLEVALUEPIXELS; i++) {
    display.drawPixel(i + AXISWIDTH, 63 - (values[i + start]), WHITE);
  }
}

// Shows the time taken to sample the values shown on screen
void drawFrameTime(unsigned long us)
{
  display.setCursor(9 * CHARWIDTH, 7 * CHARHEIGHT - 2); // almost at bottom, approximately centered
  displayln("%ld us", us);
}

/********************************************/

void setup() {

  // Set up the display
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize with the I2C addr 0x3D (for the 128x64)
  display.setTextColor(WHITE);

  pinMode(TRIGGER_ENABLE_PIN, INPUT);
  pinMode(SCREEN_UPDATE_ENABLE_PIN, INPUT);
    // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("init start");


  if (!SD.begin(chipSelect)) {
    Serial.println("fail");
    // don't do anything more:
    while (1);
  }
  Serial.println("init ok");
}

/********************************************/

void loop() {

  // If a sampling run is about to start, record the start time
  if ( pos == 0 )
    readStartTime = micros();

  // If this iteration is one we want a sample for, take the sample
  if ( (++count) % sampleRate == 0 )
    values[pos++] = analogRead(0) &gt;&gt; 4; // shifting right by 4 efficiently maps 0-1023 range to 0-63

  // If we have filled the sample buffer, display the results on screen
  if ( pos &gt;= NUMVALUES ) {
    // Measure how long the run took
    unsigned long totalSampleTime = (micros() - readStartTime) / 2;     // Divide by 2 because we are taking twice as many samples as are shown on the screen

    if ( !digitalRead(SCREEN_UPDATE_ENABLE_PIN) ) {
      // Display the data on screen   
      display.clearDisplay();
      drawAxis();
      drawValues();
      drawFrameTime(totalSampleTime);
      display.display();
    }

    // Reset values for the next sampling run
    pos = 0;
    count = 0;
  }
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin &lt; 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
      dataString += ",";
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}
</code></pre>
 33226: <h2>Few things to consider :</h2>

<ul>
<li>Each variable in your program take memory, try to use the smallest datatype ( don't use a float if you need an int for example).</li>
<li>Eliminate strings </li>
<li>Reduce the usage of array</li>
<li>Reduce your code size by using function for redudant task</li>
<li>Avoid using digital and analog red/write. Use port manipulation instead (link <a href="https://www.arduino.cc/en/Reference/PortManipulation" rel="nofollow noreferrer">here</a>)</li>
<li>Modify library to remove unused code inside </li>
<li>Use ICSP programmer instead of serial bootloader </li>
<li>Simplify your code for reducing its size. </li>
</ul>

<h2>Or simply ...</h2>

<p>Use another board such as STM32 ou bigger ATmega chip with more RAM and bigger ROM size ...  </p>
