OC
OceanRemote
Low-code IoT platform

🔧 ESP32 Low Memory Crash - Complete Fix Guide

⚠️ Symptom: Your ESP32 crashes with "abort()" messages, heap allocation failures, or spontaneous reboots after running for minutes or hours.

🔍 Common Causes of Memory Crashes

  • 📌 Memory Leaks – Allocated memory never freed. Every loop iteration allocates without deallocation.
  • 📌 Heap Fragmentation – Memory allocated/freed in patterns that fragment the heap.
  • 📌 Large Stack Allocations – ESP32 stack is only ~8KB, easily overflowed by large arrays.
  • 📌 PSRAM Not Enabled – External PSRAM available but not configured.
  • 📌 String Concatenation Loops – Building strings in loops creates temporary allocations.
  • 📌 Unclosed Resources – WiFi connections, files, or HTTP clients not properly closed.

📊 ESP32 Memory Layout Reference

Memory TypeTotal SizeCommon Issues
Internal RAM520 KBMost common bottleneck
Stack~8 KBOverflow with large local arrays
PSRAM2-8 MBMust be enabled; slower than internal
Flash4-16 MBProgram code, not for runtime allocation
RTC Memory8 KBPersists through deep sleep only

1️⃣ Monitor Memory Usage in Real Time

Add this diagnostic code to track heap memory:

void printMemoryStats() {
  Serial.print("Free heap: ");
  Serial.print(ESP.getFreeHeap());
  Serial.print(" / ");
  Serial.println(ESP.getHeapSize());
  Serial.print("Largest free block: ");
  Serial.println(ESP.getMaxAllocHeap());
}

2️⃣ Fix Memory Leaks in Loops

❌ WRONG - Memory leak:

for (int i = 0; i < 1000; i++) {
  String data = "Value: " + String(i);
  Serial.println(data);
}

✅ CORRECT - Reuse variable:

String data;
for (int i = 0; i < 1000; i++) {
  data = "Value: " + String(i);
  Serial.println(data);
}
data = "";

3️⃣ Use PSRAM for Large Allocations

In Arduino IDE: Tools → PSRAM → "Enabled"

void* largeBuffer = ps_malloc(100 * 1024);
if (largeBuffer == NULL) {
  Serial.println("PSRAM allocation failed!");
  return;
}
// Use buffer...
free(largeBuffer);

4️⃣ Avoid Large Stack Allocations

❌ WRONG - On stack (can overflow):

void processData() {
  uint8_t largeBuffer[10000];
}

✅ CORRECT - On heap:

void processData() {
  uint8_t* largeBuffer = malloc(10000);
  if (!largeBuffer) return;
  // Use buffer...
  free(largeBuffer);
}

5️⃣ Properly Close Network Resources

HTTPClient http;
http.begin("http://example.com");
int httpCode = http.GET();
if (httpCode > 0) {
  String payload = http.getString();
}
http.end();  // CRITICAL: Free resources

✅ Prevention Tips

  • Always pair malloc() with free() and new with delete
  • Allocate long-lived resources during setup(), not in loop()
  • Enable and use PSRAM for buffers larger than 50KB
  • Regularly monitor heap size during development
  • Use PROGMEM for constant strings and tables

❓ Frequently Asked Questions

Q: How much memory does an empty ESP32 sketch use?

A: About 150-180KB of the 520KB available. This leaves roughly 340KB for your application.

Q: Is PSRAM as fast as internal RAM?

A: No. Internal RAM is ~10-20x faster. Use PSRAM only for large buffers that don't need frequent access.

Q: My device runs fine for hours then crashes. Is that a memory leak?

A: Very likely. Use the memory monitoring code above to confirm if free heap steadily decreases.

Q: Does OceanRemote help with memory optimization?

A: Yes! OceanRemote generates optimized firmware with memory management built-in. Generate your firmware →

🚀 Need a Simpler Solution?

OceanRemote generates optimized firmware with:

  • ✓ Automatic memory management
  • ✓ Efficient heap usage
  • ✓ PSRAM support built-in
  • ✓ No coding required
Generate Firmware →

✅ Quick Checklist