I have an Application that is related to ApplicationFile :
/** * @ORM\OneToMany( * targetEntity="AppBundle\Entity\ApplicationFile", * mappedBy="application", * cascade={"remove"}, * orphanRemoval=true * ) */ private $files;
The file object has a field in which binary data is stored, and can be up to 2 MB in size. Repeating a large list of applications and their files increases the use of PHP memory. I want to save it.
I tried this:
$applications = $this->em->getRepository('AppBundle:Application')->findAll(); foreach ($applications as $app) { ... foreach ($app->getFiles() as $file) { ... $this->em->detach($file); } $this->em->detach($app); }
Detaching an object should cause the object manager to stop caring for this object and delete it, but it does not unexpectedly affect the amount of memory used - it continues to increase.
Instead, I have to manually download the application files (instead of extracting them through the association method), and the memory usage is not increasing. It works:
$applications = $this->em->getRepository('AppBundle:Application')->findAll(); foreach ($applications as $app) { ... $appFiles = $this ->em ->getRepository('AppBundle:ApplicationFile') ->findBy(array('application' => $application)); foreach ($appFiles as $file) { ... $this->em->detach($file); } $this->em->detach($app); }
I used xdebug_debug_zval to track links to the $file object. In the first example, there is an additional link somewhere that explains why a memory burst occurs - PHP cannot garbage collect it!
Does anyone know why this is? Where is this sitelink and how to remove it?
EDIT . An explicit call to unset($file) at the end of its loop is not affected. At the moment there are two more references to the object (checked using xdebug_debug_zval ). One of them is contained in $file (which I can disable), but there is somewhere else that I cannot undo. Calling $this->em->clear() at the end of the main loop also has no effect.
EDIT 2: SOLUTION . The answer from @origaminal led me to a solution, so I accepted his answer, rather than providing my own.
In the first method, when I access files through an association on $application , this has the side effect of initializing the previously uninitialized collection of $files on the $application object, which I repeat in the outer loop.
Calling $em->detach($application) and $em->detach($file) only tells Doctrine UOW to stop tracking objects, but it doesnβt affect the $applications array, which I repeat on, now you have a full collection of $files that eat.
I need to disable every $application object after I have finished with it to remove all links to the downloaded $files . To do this, I modified the loops as such:
$applications = $em->getRepository('AppBundle:Application')->findAll(); $count = count($applications); for ($i = 0; $i < $count; $i++) { foreach ($applications[$i]->getFiles() as $file) { $file->getData(); $em->detach($file); unset($file); } $em->detach($applications[$i]); unset($applications[$i]);