🔧 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 Type | Total Size | Common Issues |
|---|---|---|
| Internal RAM | 520 KB | Most common bottleneck |
| Stack | ~8 KB | Overflow with large local arrays |
| PSRAM | 2-8 MB | Must be enabled; slower than internal |
| Flash | 4-16 MB | Program code, not for runtime allocation |
| RTC Memory | 8 KB | Persists 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 →
📚 Related Troubleshooting Guides
🚀 Need a Simpler Solution?
OceanRemote generates optimized firmware with:
- ✓ Automatic memory management
- ✓ Efficient heap usage
- ✓ PSRAM support built-in
- ✓ No coding required