Yii2 ActiveRecord identity map memory growth in long-running CLI batch jobs
0 reputation · 13 Sept 2025, 08:41 UTC
0 reputation · 13 Sept 2025, 08:41 UTC
Assumes Yii 2.x. Iterating over thousands of ActiveRecord rows in a console command can produce steady memory growth even when loop variables are unset after each iteration. The suspected cause is the framework's internal identity map, which retains one object instance per primary key for the duration of the process.
The goal is to confirm whether this identity-map retention is the dominant source of growth, and whether an array-based DbCache provider compounds it by holding large result sets for the life of a persistent CLI process. No specific incident has been observed; this is a design-diagnosis question.
Can the ActiveRecord identity map be bounded globally or disabled for a single query? Does DbCache with an array-based provider retain cached result sets for the lifetime of a persistent CLI process? What is the supported way to release identity-map entries between batches without resetting the entire DB schema?
35775 reputation · 13 Sept 2025, 20:24 UTC
Yes. Yii2 ActiveRecord keeps one object instance per primary key in a process-wide static cache. In a long-running console command that iterates thousands of rows, that cache grows monotonically unless you clear it. An array-based DbCache provider also holds query results in RAM for the lifetime of the process, compounding growth.
ActiveRecord::$instanceCache. It is a static array that lives for the entire PHP process.ActiveRecord::$enableIdentityMap to turn the map on/off globally, and ActiveRecord::clearInstanceCache() to empty the static array without touching the database.DbCache with an in-memory provider such as ArrayCache stores cached results in PHP memory for the process lifetime. The cache is not evicted between batches.asArray() or a plain DbCommand bypasses ActiveRecord objects entirely, so no identity-map entries are created for that query.Likely explanation: steady memory growth in your console command is dominated by the identity map retaining AR objects, and possibly by ArrayCache holding large result sets. This is consistent with Yii2 design, but the dominant source in your specific job can only be confirmed by measuring memory_get_usage() before/after clearInstanceCache() and inspecting cache size.
Set before the batch starts, in Yii 2.0.27+:
\yii\db\ActiveRecord::$enableIdentityMap = false;
This disables identity-map population for the whole process. It can break code that relies on AR identity, e.g., relation caching and findOne() returning the same instance within the same request. Use only when the batch does not depend on identity semantics.
Keep identity map enabled but clear it per chunk:
$query = Model::find()->where([...])->orderBy('id');
foreach ($query->batch(1000) as $rows) {
foreach ($rows as $model) {
// process
}
\yii\db\ActiveRecord::clearInstanceCache();
// optional: gc_collect_cycles();
}
clearInstanceCache() empties the static instance cache only. It does not reset DB schema, connections, or other caches.
Model::find()->asArray()->batch(1000) to get arrays instead of objects.DbCommand for pure projection.Yes. With ArrayCache the cache lives in PHP memory for the lifetime of the persistent CLI process. Repeated DbCache queries will keep the serialized result sets in RAM until the process ends or you manually $cache->flush(). For long-running CLI jobs avoid ArrayCache for query caching; use a file or Redis provider, or disable DbCache for the batch.
clearInstanceCache() and log again.count(\yii\db\ActiveRecord::$instanceCache) before/after clearing.One missing detail that changes the recommendation: which Yii 2.x version is in use. $enableIdentityMap and clearInstanceCache() are documented from 2.0.27 onward; earlier releases lack these APIs and require the asArray()/DbCommand workaround.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.