Orm 内存泄漏Symfony2 Doctrine2/超出内存限制

Orm 内存泄漏Symfony2 Doctrine2/超出内存限制,orm,memory-leaks,symfony,doctrine-orm,Orm,Memory Leaks,Symfony,Doctrine Orm,我对symfony2和doctrine2的结合有很多困难。我必须处理巨大的数据集(大约200-300万个写和读),并且必须做很多额外的工作来避免内存不足 我列举了两个要点,即“泄漏”内存(它们实际上并不是真正的泄漏,而是分配了大量内存) Entitymanager实体存储(我不知道这个实体的真实名称)它似乎保存了所有已处理的实体,您必须定期使用 $entityManager->clear() $entityManager->clear() 原则QueryCache——它缓存所有使用过的查询,我

我对symfony2和doctrine2的结合有很多困难。我必须处理巨大的数据集(大约200-300万个写和读),并且必须做很多额外的工作来避免内存不足

我列举了两个要点,即“泄漏”内存(它们实际上并不是真正的泄漏,而是分配了大量内存)

  • Entitymanager实体存储(我不知道这个实体的真实名称)它似乎保存了所有已处理的实体,您必须定期使用

    $entityManager->clear() $entityManager->clear()
  • 原则QueryCache——它缓存所有使用过的查询,我发现的唯一配置是,您可以决定要使用哪种缓存。我没有找到全局禁用,也没有为每个查询找到一个有用的标志来禁用它。 因此,通常我使用函数对每个查询对象禁用它

    $qb = $repository->createQueryBuilder($a); $query = $qb->getQuery(); $query->useQueryCache(false); $query->execute(); $qb=$repository->createQueryBuilder($a); $query=$qb->getQuery(); $query->useQueryCache(false); $query->execute();
  • 所以。。这就是我现在知道的。。 我的问题是:

    是否有一种简单的方法可以拒绝EntityManager存储中的某些对象? 有没有办法在entitymanager中设置querycache的使用? 我可以在Symfony/doctor配置中的某个地方配置此缓存行为吗

    如果有人能给我一些好的建议,那就太酷了。。否则这可能会帮助一些新手

    正如SQL连接的默认日志记录所述,cya将设置为kernel.debug的值,因此,如果您已实例化AppKernel,并将debug设置为true,则每次迭代都会将SQL命令存储在内存中

    在使用EntityManager之前,您应该将AppKernel实例化为false,在配置YML中将logging设置为false,或者手动将SQLLogger设置为null

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

    尝试使用--无调试运行命令。在调试模式下,探查器会在内存中保留关于每个查询的信息。

    在柏林的symfony live上从条令开发者那里得到了一些“有趣”的消息-他们说,在大批量情况下,我们不应该使用orm。。在oop中构建这样的东西是没有效率的


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

    尝试禁用任何现有的条令缓存。(如果不使用APC/other作为缓存,则使用内存)

    删除查询缓存

    $qb = $repository->createQueryBuilder($a);
    $query = $qb->getQuery();
    $query->useQueryCache(false);
    $query->useResultCache(false);
    $query->execute();
    
    没有办法全局禁用它

    此外,这也是一种可能有帮助的清除方法(从)


    根据标准Doctrine2文档,您需要手动清除或删除实体

    除此之外,当启用评测时(如在默认开发环境中)。Symfony2中的DoctrineBundle配置了多个记录器,并使用了大量内存。您可以完全禁用日志记录,但这不是必需的

    一个有趣的副作用是,记录器同时影响ORM和DBAL。其中一个记录器将导致使用默认记录器服务的任何服务的额外内存使用。在命令中禁用所有这些都是理想的——因为分析器还没有在那里使用

    以下是在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);
    }
    
  • 将SQL logger设置为null
  • $em->getConnection()->getConfiguration()->setSQLLogger(null)

  • $em->clear()之后手动调用函数
    gc\u collect\u cycles()
  • $em->clear();
    gc_collect_cycles();
    

    不要忘记设置为1,或在使用前手动调用

  • 如果从控制台运行命令,则添加
    --无调试
    选项

  • 1。关闭
    app/config/config.yml中的日志记录和分析

    原则:
    dbal:
    司机:。。。
    ...
    日志记录:false
    剖析:假
    
    还是用代码

    $this->entityManager->getConnection()->getConfiguration()->setSQLLogger(null);
    
    2。强制垃圾收集器。若您积极使用CPU,那个么垃圾收集器会等待,很快您就会发现自己并没有内存

    首先启用手动垃圾收集管理。在代码中的任意位置运行
    gc\u enable()。然后运行
    gc\u collect\u cycles()
    强制垃圾收集器

    范例

    public函数执行(InputInterface$input,OutputInterface$output)
    {
    gc_enable();
    //我正在使用DependencyInjection在_构造中初始化$this->entityManager
    $customers=$this->entityManager->getRepository(Customer::class)->findAll();
    $counter=0;
    foreach($customers作为$customer){
    //处理客户-这里有一些逻辑,$this->em->persist等等
    如果(++$counter%100==0){
    $this->entityManager->flush();//保存未保存的更改
    $this->entityManager->clear();//清除条令管理的实体
    gc_collect_cycles();//PHP垃圾收集
    //请注意,$this->entityManager->clear()分离所有托管实体,
    //也许你需要一些,把它们放在这里
    }
    }
    //最后别忘了冲洗
    $this->entityManager->flush();
    $this->entityManager->clear();
    gc_collect_cycles();
    }
    

    如果您的表非常大,请不要使用
    findAll
    。使用迭代器-

    我刚刚发布了一系列将Symfony控制台命令与条令一起用于批处理的技巧。

    D2 ORM层并不是真正为大规模批处理而设计的。您最好使用DBAL层,只使用数组。使用--no debug运行会有很大帮助(在调试模式下,探查器会在内存中保留关于每个查询的信息)太棒了!几个月来我们一直在为这个问题绞尽脑汁!这是SF2的问题。你真的需要阅读文档和代码来理解它是如何工作的。前几天,我们发现我们没有在请求之间缓存DQL和元数据。我们这样做了,请求速度比变更前快了一倍,这是非常重要的
    $this->entityManager->getConnection()->getConfiguration()->setSQLLogger(null);