ESP8266 Low Memory Crash
Fix heap fragmentation, memory leaks, and insufficient RAM issues causing random reboots
10 min read
Symptoms
- Device reboots randomly every few minutes or hours
- Serial monitor shows: "Fatal exception 28" or "wdt reset"
- Out-of-memory error messages before reboot
- Crashes worsen over time
- Device resets when performing normal operations
Common Causes
- Memory leaks: malloc() without paired free(), string concatenation without cleanup
- Heap fragmentation: Many small allocs/deallocs create unusable fragments
- Stack overflow: Large local arrays/buffers consume stack space
- Inefficient WiFi code: WiFi connections without yield() cause WDT timeout
- String concatenation: String + String + String causes multiple allocations
- Missing resource cleanup: HTTP clients, WiFi scans, file handles not closed
Memory Reference Table
| Memory Type | Size | Used For |
| Internal RAM | 160 KB | Heap + Stack |
| Stack | ~4-8 KB | Local variables, call frames |
| Heap | ~150 KB | malloc(), String objects |
| Flash | Varies | File storage, EEPROM |
Step-by-Step Fixes
1. Monitor Heap Memory
Track free memory to identify when crashes occur:
void printMemoryStats() {
uint32_t free = ESP.getFreeHeap();
uint16_t maxFree = ESP.getMaxFreeBlockSize();
Serial.print; Serial.print; Serial.println;
Serial.print; Serial.print; Serial.println;
Serial.print;
Serial.println) / free);
Serial.println();
}
void loop() {
printMemoryStats();
delay;
}
2. Find Memory Leaks
Always pair malloc() with free():
// WRONG - Memory leak
void fetchData() {
char* buffer = (char*)malloc;
// ... use buffer ...
// Missing free - LEAK!
}
// CORRECT - Proper cleanup
void fetchData() {
char* buffer = (char*)malloc;
// ... use buffer ...
free; // Restore memory
}
3. Avoid String Concatenation
Use StringBuilder patterns instead:
// WRONG - Multiple allocations
String msg = "Device: " + deviceID + " Status: " + status + " Value: " + value;
// CORRECT - Single buffer
char buffer[256];
snprintf, "Device: %s Status: %s Value: %d",
deviceID, status, value);
String msg = buffer;
4. Use yield() in Loops
Prevent watchdog timeout that causes resets:
void connectWiFi() {
WiFi.begin;
int attempts = 0;
while != WL_CONNECTED && attempts < 20) {
delay;
yield(); // Feed watchdog, allow background tasks
attempts++;
}
}
5. Close WiFi Scans Properly
WiFi.scanNetworks() allocates large buffers:
void scanNetworks() {
int n = WiFi.scanNetworks();
for {
Serial.println);
}
WiFi.scanDelete(); // FREE memory from scan
}
6. Optimize SPIFFS Allocation
Reduce SPIFFS partition to give more RAM to heap:
// Arduino IDE: Tools Flash Size Select smaller SPIFFS
// Example: 2MB ~150KB heap
// Check your partition size:
FSInfo fsInfo;
SPIFFS.info;
Serial.print; Serial.println;
Prevention Tips
- Always pair malloc() with free() - never leave memory dangling
- Avoid concatenating Strings; use snprintf() or StringBuilder patterns
- Call yield() in all loops to feed the watchdog timer
- Use WiFi.scanDelete() after WiFi.scanNetworks() to free memory
FAQ
Q: How much free memory do I need to operate safely?
A: Keep at least 20-30KB free. Below 10KB, crashes become likely. Monitor with ESP.getFreeHeap().
Q: What causes "Fatal exception 28"?
A: LoadProhibited means accessing invalid memory address .
Q: Can I use PSRAM on ESP8266?
A: No. Only ESP32 supports external PSRAM. ESP8266 is limited to 160KB internal RAM.
Still having issues? Contact Support or return to the Troubleshooting Hub.