fix(layout): reserve growable tree vectors up front to avoid bad_alloc
Reserve nodes/specs/styles/labelAt/labels at reset() while the heap still has a large contiguous block. A doubling realloc mid-build needs old+new buffers live at once and throws bad_alloc on the heap the build itself has fragmented; the styles vector was the one tripping the firmware's global new-handler into a reset with ~10 populated cards. UNVALIDATED: reproduced and fixed in the emulator only. Hardware has ~30KB less free (NimBLE DMA buffers), so the reserves at reset() may still be marginal there -- not yet tested on the board.
This commit is contained in:
@@ -144,7 +144,10 @@ public:
|
||||
// Growth doubling needs the old and new buffers live at once, which is the
|
||||
// allocation that fails first on a tight heap. One reservation covers a
|
||||
// typical screen so a build reallocates only if it genuinely gets large.
|
||||
static constexpr size_t RESERVE = 64;
|
||||
// 512 skips most growth-doubling reallocs during a build (a typical screen is
|
||||
// ~300 nodes); 64 forced 4-5 doubling moves, each fragmenting the heap while
|
||||
// old and new buffers are both live.
|
||||
static constexpr size_t RESERVE = 512;
|
||||
|
||||
void reset() {
|
||||
focus = NONE;
|
||||
@@ -156,6 +159,14 @@ public:
|
||||
labels.clear();
|
||||
styles.clear();
|
||||
scrollState.clear();
|
||||
// Reserve every growable vector while the heap still has a large contiguous
|
||||
// block. A doubling realloc mid-build needs old+new live at once and throws
|
||||
// bad_alloc on a heap the build has already fragmented -- the styles vector
|
||||
// is what the global new-handler caught and turned into a reset. styles is
|
||||
// sparser than nodes; labels is a byte arena.
|
||||
labelAt.reserve(RESERVE);
|
||||
styles.reserve(RESERVE / 2);
|
||||
labels.reserve(1024);
|
||||
error = nullptr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user