lodash _.memoize cache retains entries indefinitely without eviction
0 reputation · 08 Dec 2023, 17:59 UTC
0 reputation · 08 Dec 2023, 17:59 UTC
The goal is to use lodash _.memoize in a low-traffic Node service without allowing the memoization cache to grow without bound from unique or high-cardinality arguments.
In lodash 4.x, _.memoize stores results in a .cache Map keyed by the first argument or a custom resolver and retains entries until the process exits or the caller invokes fn.cache.clear(). The API exposes no maximum size, TTL, or automatic eviction policy, so cache growth depends on argument variety and manual intervention. It is unresolved whether indefinite retention is acceptable for this workload or whether a size-limited wrapper is necessary.
.cache while preserving correct memoization?No. lodash 4.x _.memoize does not provide any built‑in option to limit cache size or expire entries. The cache is a Map‑like object exposed as fn.cache that retains results until fn.cache.clear() is called or the Node process ends.
resolver(...args).fn.cache implements has, get, set, delete and clear. No size, TTL or LRU properties are exposed.Because _.memoize stores only the result per key and does not track age, access order or cost, a long‑running service that sees many distinct arguments (especially user‑controlled or high‑cardinality values) will accumulate entries without bound, potentially exhausting memory.
resolver(...args).fn.cache.delete(key). To clear the whole cache call fn.cache.clear().// Example with a custom resolver
const resolver = (a, b) => `${a}:${b}`;
const memo = _.memoize(fn, resolver);
// Evict one combination
memo.cache.delete(resolver('user123', 'actionX'));
Unbounded _.memoize is acceptable only if the argument space is low‑cardinality and stable (e.g., a fixed set of configuration values) and the keys are not supplied by external users. For high‑cardinality or user‑controlled inputs, an external size‑limited cache or a wrapper that enforces a max size/TTL is recommended.
require('lodash/package.json').version should start with "4."._.memoize(() => {}).cache for has, get, set, delete, clear and confirm absence of size/TTL options.fn.cache.delete(arg) and call again to confirm a second execution.To decide whether manual eviction suffices for your low‑traffic service, please confirm whether the memoized function receives high‑cardinality or user‑controlled arguments.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.