In Vue 3, how does `<KeepAlive :max>` decide which cached instance to destroy, and what happens to the evicted instance?
answer
- bounded cache, not a timer
- a hit refreshes recency
- eviction on insert of a new key
- real unmount, not deactivation
basics
~20 sVue's KeepAlive max behaves like an LRU cache: when adding a new entry would exceed max, the least recently accessed cached instance is destroyed. Revisiting an entry makes it most recent. The evicted instance is fully unmounted and its state is lost.
solid answer
~40 s`max` (a number, or a numeric string) caps how many instances `<KeepAlive>` holds. Internally the cache keeps keys in access order: showing a cached entry moves its key to the most-recent end, and adding a **new** key that pushes the count over `max` removes the least recently accessed entry. That entry is not merely deactivated; it is **unmounted** for real, so `onUnmounted` runs, its state is gone, and a later visit builds a fresh instance and runs `setup()` again. The active component is never the one evicted, because it was just accessed. `max` bounds memory; it does not expire entries by time and does not free anything while the count stays under the limit.
go deeper
Know that max limits how many component instances KeepAlive keeps.
Explain the LRU behaviour: hits refresh recency, a new entry over the limit evicts the least recently accessed one, and eviction is a real unmount.
Pick max from real usage patterns, account for silently lost state on eviction, and combine it with per-entity keys and include-based eviction.
Treat view caching as a memory budget with a documented policy, and keep user work that must never be lost outside evictable instances.
## Why `max` exists Every instance `<KeepAlive>` caches holds its DOM, its reactive state, its child components and every closure they captured. With per-entity keys (one cached instance per order, per document, per chat) the cache grows with every item a user opens. `max` puts a ceiling on that growth. ```vue <template> <KeepAlive :max="5"> <component :is="current" :key="currentId" /> </KeepAlive> </template> ``` `max` accepts a number or a numeric string. ## The eviction policy The Vue docs describe `max` as making `<KeepAlive>` behave like an **LRU (least recently used) cache**. Concretely, the implementation keeps cache keys in **access order**: 1. When the child being rendered is **already cached**, its key is moved to the most-recent end. Nothing is evicted. 2. When the child is **not cached yet**, its key is added at the most-recent end. 3. If, after adding, the number of keys exceeds `max`, the key at the least-recent end is pruned. So eviction happens **only when a new entry is added**, and the victim is the entry that was **accessed** longest ago, not the one created longest ago. ## A worked sequence With `:max="3"`, the user visits tabs in this order: | Visit | Cache after the visit (least to most recent) | Evicted | |---|---|---| | A | A | none | | B | A, B | none | | C | A, B, C | none | | A | B, C, A | none (A refreshed) | | D | C, A, D | B | | B | A, D, B | C (B is rebuilt fresh) | The fourth visit is the key detail: returning to A made it recent again, so B, not A, was the first to go. The last row shows the cost: B's earlier state was lost when it was evicted, so the user's return to B builds a new instance. ## What eviction does to the instance - The evicted instance is **fully unmounted**: `onBeforeUnmount` and `onUnmounted` run for it and its descendants, its effects are stopped and its DOM is released. - It already received `onDeactivated` when it was hidden earlier; eviction is the point where it is actually destroyed. - A later visit to the same key is a **fresh mount**: `setup()`, `onMounted` and `onActivated` all run, with initial state. - The **currently active** component is never evicted, because it is the most recently accessed entry. ## Other ways entries leave the cache `max` is one of three eviction paths: - **`include` / `exclude` changes**: entries whose names no longer qualify are pruned after the next render. - **`<KeepAlive>` unmounting**: every cached instance is unmounted with it. - **`max`**: least recently accessed entry pruned when a new one would exceed the limit. There is **no time-based expiry**. An entry can sit in the cache for the whole session if the count never exceeds `max`. ## Choosing a value - Size `max` to the number of views a user realistically juggles, such as the tabs visible in a tab strip, not to "everything they ever opened". - Remember that eviction loses user state silently. If losing a draft on eviction would be a bug, the draft needs to live outside the component as well. - With no `max` and per-entity keys, memory grows without bound over a long session; check heap usage after opening many items. ## Interaction with keys The cache counts **keys**, not component types. Without a `key` on the child, each component type occupies one entry, so `max` effectively limits how many different components are cached. With a `key` per entity, such as `:key="docId"`, each entity is its own entry and `max` limits how many entities stay alive. That is the combination where `max` matters most: per-entity keys give each open item its own preserved state, and `max` stops the cache from growing with every item a user ever opened during a long session. ## Summary `max` makes the KeepAlive cache an access-ordered, size-bounded cache: hits refresh recency, new entries evict the least recently accessed one beyond the limit, and eviction is a real unmount that discards the instance's state.
- Does revisiting a cached view protect it from eviction?Yes, for a while. Showing a cached entry moves its key to the most-recent end of the access order, so it becomes the last candidate for eviction. The next evictions take entries that have gone longer without being shown.
- Does `max` ever free memory when the cache is below the limit?No. `max` only evicts when adding a new key pushes the count over the limit. There is no time-based expiry, so entries can live for the whole session; use a reactive `include` list or unmount the `<KeepAlive>` to free them earlier.
A browser with a tab limit that closes the tab you looked at longest ago whenever you open a new one; reopening it later gives you a freshly loaded page.
saying these in an interview costs you the question
- max evicts the oldest-created entry, regardless of recent visits
- An evicted instance is only deactivated and can be restored with its state
- max makes cached entries expire after a period of inactivity
- The currently active component can be evicted to make room
- Without max, KeepAlive caches at most ten instances