Orm 内存泄漏Symfony2 Doctrine2/超出内存限制
我对symfony2和doctrine2的结合有很多困难。我必须处理巨大的数据集(大约200-300万个写和读),并且必须做很多额外的工作来避免内存不足 我列举了两个要点,即“泄漏”内存(它们实际上并不是真正的泄漏,而是分配了大量内存)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——它缓存所有使用过的查询,我
$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);
}
$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);