FileVisibility stores full entity objects, causing memory accumulation
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3583772. --> Reported by: [herved](https://www.drupal.org/user/2197136) Related to !15 >>> <h3 id="summary-problem-motivation">Problem/Motivation</h3> <p>FileVisibility::updateFilesVisibility() queues full entity objects in $entities[] for deferred processing via KernelEvents::RESPONSE. In long-lived processes (Drush, Behat, cron,...), these objects accumulate over the entire process lifetime, consuming significant memory since they are not garbage collected.<br> For historical context, the defer was introduced in <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/file_visibility/-/work_items/3536831" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/file_visibility/-/work_items/3536831</a></span>.</p> <p>track_usage's Recorder service, which has the same deferred processing pattern, already handles this correctly by storing lightweight identifiers (entity type, ID, revision) instead of full objects.</p> <h4 id="summary-steps-reproduce">Steps to reproduce</h4> <p>1. Fresh Drupal install</p> <pre>ddev drush si standard -y<br>ddev drush en file_visibility_track_usage -y</pre><p>2. Create a TrackConfig and point file_visibility_track_usage at it.</p> <pre>ddev drush php:eval "<br>&nbsp; \Drupal\track_usage\Entity\TrackConfig::create([<br>&nbsp;&nbsp;&nbsp; 'id'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'file_visibility',<br>&nbsp;&nbsp;&nbsp; 'label'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; 'File Visibility',<br>&nbsp;&nbsp;&nbsp; 'realTimeRecording' =&gt; TRUE,<br>&nbsp;&nbsp;&nbsp; 'activeRevision'&nbsp;&nbsp;&nbsp; =&gt; FALSE,<br>&nbsp;&nbsp;&nbsp; 'source'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; ['node' =&gt; []],<br>&nbsp;&nbsp;&nbsp; 'traversable'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; [],<br>&nbsp;&nbsp;&nbsp; 'target'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; ['file' =&gt; []],<br>&nbsp;&nbsp;&nbsp; 'status'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =&gt; TRUE,<br>&nbsp; ])-&gt;save();<br><br>&nbsp; \Drupal::configFactory()<br>&nbsp;&nbsp;&nbsp; -&gt;getEditable('file_visibility_track_usage.settings')<br>&nbsp;&nbsp;&nbsp; -&gt;set('track_usage_config', 'file_visibility')<br>&nbsp;&nbsp;&nbsp; -&gt;save();<br>&nbsp; echo 'Done.' . PHP_EOL;<br>"</pre><p>3. Save the following script below as memory_hog.php.</p> <pre>&lt;?php<br><br>gc_collect_cycles();<br>$before = memory_get_usage(FALSE);<br><br>$storage = \Drupal::entityTypeManager()-&gt;getStorage('node');<br>for ($i = 0; $i &lt; 1000; $i++) {<br>&nbsp; $node = \Drupal\node\Entity\Node::create([<br>&nbsp;&nbsp;&nbsp; 'type'&nbsp;&nbsp; =&gt; 'page',<br>&nbsp;&nbsp;&nbsp; 'title'&nbsp; =&gt; 'memtest_' . $i,<br>&nbsp;&nbsp;&nbsp; 'status' =&gt; 1,<br>&nbsp;&nbsp;&nbsp; 'uid'&nbsp;&nbsp;&nbsp; =&gt; 1,<br>&nbsp; ]);<br>&nbsp; $node-&gt;save();<br>&nbsp; $storage-&gt;delete([$node]);<br>}<br><br>gc_collect_cycles();<br>$after = memory_get_usage(FALSE);<br><br>printf("before: %.1f MB\n", $before / 1048576);<br>printf("after:&nbsp; %.1f MB\n", $after&nbsp; / 1048576);<br>printf("delta:&nbsp; %.1f MB\n", ($after - $before) / 1048576);</pre><p>4. Execute it<br> <code>ddev drush php:script memory_hog.php</code></p> <p>Notice the memory consumption is high, on my machine:</p> <pre>before: 8.5 MB<br>after:&nbsp; 58.3 MB<br>delta:&nbsp; 49.8 MB</pre><p>After provided fix:</p> <pre>before: 8.5 MB<br>after:&nbsp; 13.3 MB<br>delta:&nbsp; 4.8 MB</pre><h3 id="summary-proposed-resolution">Proposed resolution</h3> <p>Store entity type/ID/revision in FileVisibility::$entities instead of full entity objects, consistent with track_usage's Recorder.</p> <h3 id="summary-remaining-tasks">Remaining tasks</h3> <p>?</p> <h3 id="summary-ui-changes">User interface changes</h3> <p>None</p> <h3 id="summary-api-changes">API changes</h3> <p>None</p> <h3 id="summary-data-model-changes">Data model changes</h3> <p>None</p>
issue