dongzhan3937
2013-03-22 14:09 阅读 103
已采纳

Doctrine ORM Memory问题

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->clear(); // This kinda helps
  • $em->close(); // this causes issues
  • $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?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

2条回答 默认 最新

  • 已采纳
    dongxing2692 dongxing2692 2013-05-08 12:39

    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
        }
    }
    
    点赞 评论 复制链接分享
  • doupuchen6378 doupuchen6378 2013-03-22 14:56

    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.

    点赞 2 评论 复制链接分享

相关推荐