[core] Also shrink items_/to_add_/defer_queue_ vector capacity in trim_freelist()

The freelist holds the boot-peak count of recycled SchedulerItem*; items_,
to_add_, and defer_queue_ hold the boot-peak vector *capacity* of live
SchedulerItem*. std::vector grows by doubling and retains capacity even when
items drain, so post-boot the vector slack can be larger than the freelist
itself. Swap each with a same-content copy to size them exactly to their
current contents.

Live items are preserved -- the swap-copy idiom builds the new vector from
the existing pointers, then the old (over-capacity) vector is destroyed.
This commit is contained in:
J. Nick Koston
2026-04-30 11:31:13 -05:00
parent d36c56d3f5
commit 8b840e8517
2 changed files with 14 additions and 5 deletions
+10
View File
@@ -914,6 +914,16 @@ void Scheduler::trim_freelist() {
}
this->scheduler_item_pool_head_ = nullptr;
this->scheduler_item_pool_size_ = 0;
// The vectors that back items_/to_add_/defer_queue_ also retain their boot-peak
// capacity (std::vector grows by doubling). Swap each with a same-content copy to
// reclaim the slack -- the new vector is sized exactly to its current contents.
std::vector<SchedulerItem *>(this->items_).swap(this->items_);
std::vector<SchedulerItem *>(this->to_add_).swap(this->to_add_);
#ifndef ESPHOME_THREAD_SINGLE
std::vector<SchedulerItem *>(this->defer_queue_).swap(this->defer_queue_);
#endif
#ifdef ESPHOME_DEBUG_SCHEDULER
ESP_LOGD(TAG, "Freelist trimmed (%zu items freed)", freed);
#else
+4 -5
View File
@@ -132,11 +132,10 @@ class Scheduler {
// @return Timestamp of the last item that ran, or `now` unchanged if none ran.
uint32_t call(uint32_t now);
// Free every SchedulerItem currently sitting in the recycle freelist. Items in
// items_/to_add_/defer_queue_ are untouched. Intended to claim the post-boot
// peak: boot churn (component setup, first sensor reads, retries) inflates the
// freelist beyond what steady-state needs, and without a one-shot trim that
// peak would be retained forever.
// Reclaim memory held by the post-boot peak. Frees every SchedulerItem in the
// recycle freelist and shrinks items_/to_add_/defer_queue_ vector capacity to
// their current sizes (std::vector grows by doubling and otherwise retains the
// peak). Live items in those vectors are preserved.
void trim_freelist();
// Move items from to_add_ into the main heap.