内存泄漏的Symfony2 Doctrine2 /超出内存限制内存泄漏的Symfony2 Doctr

2019-05-13 09:55发布

其实我有很多的麻烦Symfony2的和doctrine2的组合。 我必须处理庞大的数据集(约2-3万的写入和读取),而且还要做很多额外的工作,以避免耗尽内存。

我figgured了2个主要的点,即“泄漏”内存荷兰国际集团(他们实际上是不是真的泄漏,但是分配了很多)

  1. EntityManager的实体存储(我不知道这其中的真名),好像它一直都处理的entites,你必须清除此存储regulary与

      $ entityManager->明确的() 
  2. 该学说实现QueryCache - 它缓存所有使用的查询,我发现的唯一配置是你能决定什么样的Cache你想使用。 我没有找到一个全球性的禁止既不是有用的标志为每个查询来禁用它。 所以通常禁用它与每个功能的查询对象

      $ QB = $ repository-> createQueryBuilder($ a)的  $查询= $ QB-> getQuery();  $查询 - > useQueryCache(假);  $查询 - >执行(); 

所以..这就是所有我想通了,现在..我的问题是:

有没有一种简单的方法来拒绝来自Entitymanagerstorage某些对象? 有没有一种方法来设置了EntityManager的实现QueryCache用? 我可以配置在symonfony学说配置这种缓存行为somethere?

将是非常酷的,如果有一个人对我一些很好的建议..否则可能帮助一些新人..

CYA

Answer 1:

有点晚了,但我想我刚刚发现了一个在谷歌论坛主题由本杰明Eberlei,回答你的问题:由所陈述的原则配置参考由SQL连接的默认日志记录设置为kernel.debug的价值,所以如果您有实例AppKernel与调试设置为true的SQL命令获取存储在内存中为每个迭代。

您应该实例AppKernel为false,设置日志记录false您配置阳明,或任一使用EntityManager之前手动设置SQLLogger为null

$em->getConnection()->getConfiguration()->setSQLLogger(null);


Answer 2:

尝试用--no调试运行你的命令。 在调试模式剖析保留有关在内存中的每一个查询信息。



Answer 3:

1.关闭记录和分析app/config/config.yml

doctrine:
    dbal:
        driver: ...
        ...
        logging: false
        profiling: false

或代码

$this->em->getConnection()->getConfiguration()->setSQLLogger(null);

2.强制垃圾收集器 。 如果积极利用CPU那么垃圾收集器等待,你可以没有记忆很快就会发现自己。

起初启用手动垃圾收集管理。 运行gc_enable()在代码的任何地方。 然后运行gc_collect_cycles()来强制垃圾收集器。

public function execute(InputInterface $input, OutputInterface $output)
{
    gc_enable();

    // I'm initing $this->em in __construct using DependencyInjection
    $customers = $this->em->getRepository('AppBundle:Customer')->findAll();

    $counter = 0;
    foreach ($customers as $customer) {
        // process customer - some logic here, $this->em->persist and so on

        if (++$counter % 100 == 0) {
            $this->em->flush(); // save unsaved changes
            $this->em->clear(); // clear doctrine managed entities
            gc_collect_cycles(); // PHP garbage collect

            // Note that $this->em->clear() detaches all managed entities,
            // may be you need some; reinit them here
        }
    }

    // don't forget to flush in the end
    $this->em->flush();
    $this->em->clear();
    gc_collect_cycles();
}

如果你的表是非常大的,不使用findAll 。 使用iterator - http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html#iterating-results



Answer 4:

  1. 设置SQL记录为空

$em->getConnection()->getConfiguration()->setSQLLogger(null);

  1. 手动调用函数gc_collect_cycles()之后$em->clear()

$em->clear(); gc_collect_cycles();

不要忘记设置zend.enable_gc 1,或手动调用gc_enable()之前使用gc_collect_cycles()

  1. 添加--no-debug ,如果你从控制台运行命令选项。


Answer 5:

接到学说开发商本身在柏林symfony的活一些“有趣”的消息 - 他们说,这对大批量,我们不应该使用ORM ..它只是没有有效建立这样的东西在空中接力

..是啊..也许他们是对的xD



Answer 6:

按照标准Doctrine2文档,则需要手动清除或detatch实体。

此外,当分析已启用(在默认开发环境)。 该DoctrineBundle在Symfony2中配置了几个记录器使用相当多的内存。 您可以完全禁用日志记录,但它不是必需的。

一个有趣的副作用,是伐木工人同时影响学说ORM和DBAL。 其中一个记录器会导致额外的内存使用情况,使用默认记录器服务的任何服务。 因为探查未使用存在尚未禁用所有这些将是commands--理想。

这里是你可以做什么来禁用内存密集型记录器,同时保持貌相Symfony2的其他部分启用:

$c = $this->getContainer();
/* 
 * The default dbalLogger is configured to keep "stopwatch" events for every query executed
 * the only way to disable this, as of Symfony 2.3, Doctrine Bundle 1.2, is to reinistiate the class
 */

$dbalLoggerClass = $c->getParameter('doctrine.dbal.logger.class');
$dbalLogger = new $dbalLoggerClass($c->get('logger'));   
$c->set('doctrine.dbal.logger', $dbalLogger);

// sometimes you need to configure doctrine to use the newly logger manually, like this
$doctrineConfiguration = $c->get('doctrine')->getManager()->getConnection()->getConfiguration();
$doctrineConfiguration->setSQLLogger($dbalLogger);

/*
 * If profiling is enabled, this service will store every query in an array
 * fortunately, this is configurable with a property "enabled"
 */
if($c->has('doctrine.dbal.logger.profiling.default'))
{
    $c->get('doctrine.dbal.logger.profiling.default')->enabled = false;
}

/*
 * When profiling is enabled, the Monolog bundle configures a DebugHandler that 
 * will store every log messgae in memory. 
 *
 * As of Monolog 1.6, to remove/disable this logger: we have to pop all the handlers
 * and then push them back on (in the correct order)
 */
$handlers = array();
try
{   
    while($handler = $logger->popHandler())
    {
        if($handler instanceOf \Symfony\Bridge\Monolog\Handler\DebugHandler)
        {
            continue;
        }
        array_unshift($handlers, $handler);
    }
}
catch(\LogicException $e)
{
    /*
     * As of Monolog 1.6, there is no way to know if there's a handler
     * available to pop off except for the \LogicException that's thrown.
     */
    if($e->getMessage() != 'You tried to pop from an empty handler stack.')
    {
        /*
         * this probably doesn't matter, and will probably break in the future
         * this is here for the sake of people not knowing what they're doing
         * so than an unknown exception is not silently discarded.
         */

        // remove at your own risk
        throw $e;
    }
}

// push the handlers back on
foreach($handlers as $handler)
{
    $logger->pushHandler($handler);
}


Answer 7:

尝试禁用存在的任何学说缓存。 (如果你不使用APC /其他作为高速缓存,然后使用内存)。

删除查询缓存

$qb = $repository->createQueryBuilder($a);
$query = $qb->getQuery();
$query->useQueryCache(false);
$query->useResultCache(false);
$query->execute();

有没有办法在全球范围内禁用它

另外这是清除可能的帮助(从另一这里 )

$connection = $em->getCurrentConnection();
$tables = $connection->getTables();
foreach ( $tables as $table ) {
    $table->clear();
}


Answer 8:

我刚刚发布了一堆提示使用Symfony的控制台命令与学说进行批处理这里 。



文章来源: Memory leaks Symfony2 Doctrine2 / exceed memory limit