【发布时间】: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