Doctrine Paginator填满内存
问题描述:
我在PHP 7.0.22上使用了Docfine Paginator的Symfony命令。该命令必须处理来自大型表格的数据,因此我以100个项目为单位进行处理。问题是,在几百个循环后,它会填充256M内存。作为对OOM措施(外的内存)我使用:Doctrine Paginator填满内存
-
$em->getConnection()->getConfiguration()->setSQLLogger(null);
- 禁用SQL记录器,填充内存用于运行许多SQL脚本记录的查询命令 -
$em->clear();
- 分离从学说中的所有对象在每次循环
我已经把一些垃圾场与memory_get_usage()
检查发生了什么事情,似乎是在命令在每次调用$paginator->getIterator()->getArrayCopy();
增加了回收不干净尽可能多的结尾。
我甚至试图手动收集垃圾每个循环与gc_collect_cycles()
,但仍然没有区别,命令开始使用18M和增加约每隔几百个项目〜2M。还试图手动取消设置结果和查询生成器...什么也没有。我删除了所有的数据处理,只保留了select查询和paginator,并得到了相同的行为。
任何人有任何想法我应该看看下一个?
注意:对于这类操作,256M应该足够了,所以请不要推荐提示增加允许内存的解决方案。
条纹下来方法看起来是这样的:由学说分页程序产生
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");
}
答
内存泄漏。我用Doctrine prepared statements用原生查询替换它并修复它。
- 如果要更换学说分页程序,你应该重建分页功能,加入了限制查询:
,你应该考虑其他的事情。
- 用
--no-debug
标志或-env=prod
或两者都可以运行命令。问题是这些命令默认在dev
环境中运行。这使得一些在prod
环境中未使用的数据收集器成为可能。查看更多关于这个主题的Symfony documentation - How to Use the Console
编辑:在我特定情况下我还使用了实现HTTP狂饮库捆绑eightpoints/guzzle-bundle
(在我的命令,某些API调用)。这个捆绑包也泄漏了,显然是通过一些中间件。为了解决这个问题,我不得不独立实例化Guzzle客户端,而没有EightPoints包。