The Problem:
While running a Daemon service that uses Doctrine from the Factory classes below there is a memory issue. When the Daemon Service starts it runs about 175MB. A day later it's about 250MB, one more day and it's at 400MB. I'm looking as to what is causing the increase in memory and how I could bring it down.
Things I've tried:
$em->getConnection()->getConfiguration()->setSQLLogger(null);
--env=prod should take care of setSQLLogger(null), correct?
Is there anything I should be doing to help with memory issues using Doctrine 2.x and Symfony 2.1.x?
Created a factory to handle connections
===================== START EMFactory =====================
<?php
namespace NS\Bundle\EMBundle;
use Doctrine\ORM\EntityManager;
class EMFactory
{
/**
* @var
*/
private $container;
/**
* @param $container
*/
public function __construct($container)
{
$this->container = $container;
}
/**
* @return EntityManager
*/
public function getBlahEntityManager()
{
return $this->getContainer()->get('doctrine.orm.blah_manager_entity_manager');
}
/**
* @return EntityManager
*/
public function getFooEntityManager()
{
return $this->getContainer()->get('doctrine.orm.foo_manager_entity_manager');
}
/**
* @return EntityManager
*/
public function getBarEntityManager()
{
return $this->getContainer()->get('doctrine.orm.bar_manager_entity_manager');
}
/**
* @return mixed
*/
public function getContainer()
{
return $this->container;
}
/**
* @param $container
* @return $this
*/
public function setContainer($container)
{
$this->container = $container;
return $this;
}
public function closeEntityManager(EntityManager $em)
{
try {
$em->clear(); // This kinda helps
//$em->close(); // this causes issues
//$em->getConnection()->getConfiguration()->setSQLLogger(null); // --env=prod should take care of this
} catch (\Exception $e) {
// exception here
}
}
}
===================== END EMFactory =====================
I use an Abstract Class that constructs the EMFactory
===================== Start Abstract Class =====================
/**
* @param \Symfony\Component\DependencyInjection\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
$this->entityManagerFactory = new EMFactory($container);
}
===================== END Abstract Class =====================
Here is an example of how I'm using the EM, The class extends the Abstract class above
===================== START Working Example #1 =====================
// calling like this looks to be working as expected
$fooEM = $this->getEntityManagerFactory()->getFooEntityManager();
$barResults = $fooEM->getRepository('NS\Bundle\EMBundle\Entity\Bar')->findOneBy(array('id' => 1));
if (!is_object($barResults)) {
throw new \Exception("Bar is a non object.");
}
// some logic here ...
$this->getEntityManagerFactory()->closeEntityManager($fooEM);
===================== END Working Example #1 =====================
Here is another example of how I'm using the EM, The class extends the Abstract class above
===================== START Working Example #2 =====================
// calling from functions like this
$fooEM = $this->getEntityManagerFactory()->getFooEntityManager();
$dql = 'SELECT b.*
FROM NS\Bundle\EMBundle\Entity\Bar b
WHERE b.id = :id';
$query = $fooEM->createQuery($dql);
$query->setParameter('id', 1);
$barResults = $query->getResult();
$this->getEntityManagerFactory()->closeEntityManager($fooEM);
return $barResults;
===================== END Working Example #2 =====================
Here is another example of how I'm using the EM, The class extends the Abstract class above
===================== START Working Example #3 =====================
// calling from functions like this
$fooEM = $this->getEntityManagerFactory()->getFooEntityManager();
$barEntity = new Bar();
$barEntity->setId(1);
$barEntity->setComment('this is foo-ie');
$fooEM->persist($barEntity);
$fooEM->flush();
$this->getEntityManagerFactory()->closeEntityManager($fooEM);
unset($barEntity);
===================== END Working Example #3 =====================
These are just some basic examples but it's just the queries that get more complex.
Does anything stand out that say, Optimize me?
This solved the connection issue we were having.
Needed to close just the connection
public function closeEntityManager(EntityManager $em)
{
try {
$em->clear(); // This kinda helps
$em->getConnection()->close(); // this seems to work
} catch (\Exception $e) {
// exception here
}
}
Your issue might come from your instanciations of your entity managers. If you have a specific set of them, you might rather use Symfony2 Dependency Injection instead of calling the container.
Each time you use your accessors, you'll instantiate a new Entity Manager, hence consume more memory (and as it's a daemon, you never truly release it). By using DI, you'll always have the same instance.
Your EMFFactory should then look like this:
<?php
namespace NS\Bundle\EMBundle;
use Doctrine\ORM\EntityManager;
class EMFactory
{
/**
* @var
*/
private $fooEm;
/**
* @var
*/
private $barEm;
/**
* @var
*/
private $blahEm;
/**
* @param $fooEm
* @param $barEm
* @param $blahEm
*/
public function __construct($fooEm, $barEm, $blahEm)
{
$this->fooEm = $fooEm;
$this->barEm = $barEm;
$this->blahEm = $blahEm;
}
/**
* @return EntityManager
*/
public function getBlahEntityManager()
{
return $this->blahEm;
}
/**
* @return EntityManager
*/
public function getFooEntityManager()
{
return $this->fooEm;
}
/**
* @return EntityManager
*/
public function getBarEntityManager()
{
return $this->barEm;
}
/**
* @return mixed
*/
public function getContainer()
{
return $this->container;
}
/**
* @param $container
* @return $this
*/
public function setContainer($container)
{
$this->container = $container;
return $this;
}
public function closeEntityManager(EntityManager $em)
{
try {
$em->clear(); // This kinda helps
//$em->close(); // this causes issues
//$em->getConnection()->getConfiguration()->setSQLLogger(null); // --env=prod should take care of this
} catch (\Exception $e) {
// exception here
}
}
}
Then, tweak your service definitions to give the various EMs to your config, and define your EMFactory as a service as well.