【问题标题】:Doctrine Paginator fills up memoryDoctrine Paginator 填满内存
【发布时间】:2018-03-06 17:01:23
【问题描述】:

我有一个在 PHP 7.0.22 上使用 Doctrine Paginator 的 Symfony 命令。该命令必须处理来自大表的数据,因此我以 100 个项目为一组进行处理。问题是,经过几百次循环后,它会填满 256M RAM。作为针对 OOM(内存不足)的措施,我使用:

  • $em->getConnection()->getConfiguration()->setSQLLogger(null); - 禁用 sql 记录器,该记录器会使用运行许多 sql 命令的脚本的记录查询来填充内存
  • $em->clear(); - 在每个循环结束时从 Doctrine 中分离所有对象

我用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("\n\n<info>Done running <comment>" . $this->getName() . "</comment></info>\n");
}

【问题讨论】:

  • 是的,同样的问题,归结为 ->setFirstResult(...) 函数,它会导致内存增加。仍在寻找答案

标签: php symfony memory-management doctrine-orm pagination


【解决方案1】:

内存泄漏是由 Doctrine Paginator 产生的。我使用Doctrine prepared statements 将其替换为本机查询并修复了它。

您应该考虑的其他事项:

  • 如果您要替换 Doctrine Paginator,则应通过向查询添加限制来重建分页功能。
  • 使用--no-debug 标志或-env=prod 或两者都运行您的命令。问题是这些命令默认在dev 环境中运行。这启用了prod 环境中未使用的一些数据收集器。在Symfony documentation - How to Use the Console 中查看有关此主题的更多信息

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-28
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    相关资源
    最近更新 更多