Skip to content

fix: prevent OOM crash when loading large EPUBs (2000+ chapters)#457

Closed
DChells wants to merge 1 commit intocrosspoint-reader:masterfrom
DChells:fix/large-epub-oom
Closed

fix: prevent OOM crash when loading large EPUBs (2000+ chapters)#457
DChells wants to merge 1 commit intocrosspoint-reader:masterfrom
DChells:fix/large-epub-oom

Conversation

@DChells
Copy link
Contributor

@DChells DChells commented Jan 20, 2026

Summary

Fixes #134 - Large EPUBs with 2000+ chapters (common in webnovels) crash the device during initial indexing.

Problem

When loading a large EPUB, buildBookBin() calls loadAllFileStatSlims() which pre-loads ALL ZIP central directory entries into a std::unordered_map<std::string, FileStatSlim>. For EPUBs like "Shadow Slave" (2773 entries) or "Lord of Mysteries" (1400+ entries), this exhausts ESP32-C3's ~380KB RAM and triggers abort().

Serial log evidence:

[61679] [EBP] Loading ePub: /Books/Shadow Slave...
[567904] [BMC] Wrote 2768 spine, 2768 TOC entries
abort() was called at PC 0x420e61ad on core 0

Solution

Remove the loadAllFileStatSlims() call. The existing loadFileStatSlim() function already handles individual lookups by scanning the ZIP central directory per-file when the cache is empty.

Trade-off: This is O(n×m) instead of O(n) for lookups, making initial indexing slower for large EPUBs. However, it prevents memory exhaustion and allows the book to load successfully. A future optimization could cache only spine item stats rather than all ZIP entries.

Testing

  • Build passes
  • Normal EPUBs still load correctly
  • Large EPUB (2000+ chapters) no longer crashes during initial load
  • Large EPUB indexes successfully (may take several minutes)

Notes

This addresses the TODO comment that was already in the code acknowledging this issue.

Remove the call to loadAllFileStatSlims() which pre-loads all ZIP central
directory entries into memory. For EPUBs with 2000+ chapters (like webnovels),
this exhausts the ESP32-C3's ~380KB RAM and causes abort().

The existing loadFileStatSlim() function already handles individual lookups
by scanning the central directory per-file when the cache is empty. This is
O(n*m) instead of O(n), but prevents memory exhaustion.

Fixes crosspoint-reader#134
@DChells
Copy link
Contributor Author

DChells commented Jan 21, 2026

Test Results ✅

Tested on Xteink X4 e-reader with CrossPoint community firmware.

Test Case: Shadow Slave (2768 chapters, 2773 ZIP entries)

Before this PR: Device crashed immediately during initial indexing due to OOM when loadAllFileStatSlims() attempted to load all ZIP entries (~200KB+) into ESP32-C3's ~380KB RAM.

After this PR: Book indexed successfully!

[1556504] [BMC] Successfully built book.bin
  • Indexing time: ~25.5 minutes (expected for 2768 chapters with sequential ZIP reads)
  • No crash at any point
  • Book opens and chapters are navigable

Analysis

The fix correctly addresses the root cause: loadAllFileStatSlims() was pre-loading all ZIP central directory entries into RAM to speed up lookups, but for large EPUBs this exceeded available memory.

By removing this call and falling back to sequential ZIP reads, we trade indexing speed for memory safety. This is the correct tradeoff for a memory-constrained device.

Copy link
Member

@daveallie daveallie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please compare the initial load times for some other epubs. I specifically wrote loadAllFileStatSlims and added it here to avoid the O(n^2) issue of scanning through the zip central directory for each file.

imo a 25 minute load time is pretty unacceptable and we should just crash out. Especially if it significantly slows down opening previously ok files.

@DChells
Copy link
Contributor Author

DChells commented Jan 22, 2026

Closing as superseded by #458, which includes both the OOM fix (skipping loadAllFileStatSlims()) and performance optimizations that reduce indexing from ~30 min to ~50 sec.

@DChells DChells closed this Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upon opening an epub file, it just loads

2 participants