学说的Paginator填充了内存



我有一个Symfony命令,该命令使用PHP 7.0.22上的学说Paginator。该命令必须从大表格处理数据,因此我在100个项目的块中进行此操作。问题是,经过几百个循环,它填充了2.56亿RAM。作为针对OOM的措施(暂时),我使用:

  • $em->getConnection()->getConfiguration()->setSQLLogger(null);-禁用SQL Logger,该记录器填充存储器的记录查询,用于运行许多SQL命令的脚本
  • $em->clear();-在每个循环结束时将所有对象从学说中分离

我已经放了一些memory_get_usage()的转储来检查正在发生的事情,看来收集器没有像命令在每个$paginator->getIterator()->getArrayCopy();呼叫时那样清洁。

我什至尝试用gc_collect_cycles()手动收集每个环的垃圾,但仍然没有区别,命令开始使用18m,每百个项目以约2m的速度增加。还试图手动拆除结果和查询构建器...什么都没有。我删除了所有数据处理,仅保留了选择查询和吊架并获得相同的行为。

任何人都知道我应该在哪里看?

注意: 256m应该足以容纳这种操作,因此请勿建议您建议增加允许内存的解决方案。

条纹下调的execute()方法看起来像这样:

protected function execute(InputInterface $input, OutputInterface $output)
{
    // Remove SQL logger to avoid out of memory errors
    $em = $this->getEntityManager(); // method defined in base class
    $em->getConnection()->getConfiguration()->setSQLLogger(null);

    $firstResult = 0;

    // Get latest ID
    $maxId = $this->getMaxIdInTable('AppBundle:MyEntity'); // method defined in base class
    $this->getLogger()->info('Working for max media id: ' . $maxId);
    do {
        // Get data
        $dbItemsQuery = $em->createQueryBuilder()
            ->select('m')
            ->from('AppBundle:MyEntity', 'm')
            ->where('m.id <= :maxId')
            ->setParameter('maxId', $maxId)
            ->setFirstResult($firstResult)
            ->setMaxResults(self::PAGE_SIZE)
        ;
        $paginator = new Paginator($dbItemsQuery);
        $dbItems = $paginator->getIterator()->getArrayCopy();
        $totalCount = count($paginator);
        $currentPageCount = count($dbItems);
        // Clear Doctrine objects from memory
        $em->clear();

        // Update first result
        $firstResult += $currentPageCount;
        $output->writeln($firstResult);
    } 
    while ($currentPageCount == self::PAGE_SIZE);

    // Finish message
    $output->writeln("nn<info>Done running <comment>" . $this->getName() . "</comment></info>n");
}

记忆泄漏是由学说的Paginator生成的。我用准备好的语句用本机查询替换了它并修复了它。

您应该考虑的其他事情:

  • 如果您要替换学说的编织者,则应通过在查询中添加限制来重建分页功能。
  • 使用--no-debug标志或-env=prod或两者都运行命令。问题是命令在dev环境中默认运行。这使一些数据收集器可以在prod环境中使用。在Symfony文档中查看有关此主题的更多信息 - 如何使用控制台

编辑:在我的特定情况下我还使用了实现HTTP Guzzle库的捆绑eightpoints/guzzle-bundle(我的命令中有一些API调用)。这个捆绑包也泄漏了,显然是通过一些中间件。为了解决此问题,我必须独立实例化guzzle客户端,而无需八点捆绑。

相关内容

  • 没有找到相关文章

最新更新