我有一个php脚本,使用Doctrine2和Zend从数据库中计算一些东西,并为30,000用户发送一些电子邮件。
我的脚本正在泄漏内存,我想知道哪些对象正在消耗内存,如果可能的话,谁在保持对它们的引用(因此不允许它们被释放)。
我使用php 5.3。X,所以简单的循环引用应该不是问题。
我尝试使用xdebug跟踪功能来获取mem_delta,但没有成功(数据太多)。
我尝试在重要函数之前和之后手动添加memory_get_usage。但我得到的唯一结论是,我每个用户损失了大约400k, 3000个用户乘以这个,我就有了1Gb的可用空间。
是否有其他方法知道内存泄漏的位置和原因?由于
你可以试着发送10封邮件然后插入这个
get_defined_vars();
http://nz.php.net/manual/en/function.get-defined-vars.php 在脚本的末尾或在电子邮件发送之后(取决于你的代码是如何设置的)。
这应该告诉你哪些仍然被加载,哪些可以取消设置/转换为引用。
如果加载了很多东西,你可以在代码的开始和结束处设置这个,并计算出差异
3万个物体需要水合物是相当多的。原则2是稳定的,但有一些bug,所以我不太惊讶你的内存泄漏问题。
虽然对于较小的数据集,我使用doctrine批处理功能并创建可迭代的结果取得了一些成功。
您可以使用示例中的代码,并在每次迭代后添加一个gc_collect_cycles()
。你必须测试它,但对我来说,批处理大小在100左右工作得很好——这个数字在性能和内存使用之间取得了很好的平衡。
这是相当重要的,脚本识别哪些实体被处理,以便它可以重新启动没有任何问题,并恢复正常的操作,而不发送两次电子邮件。
$batchSize = 20;
$i = 0;
$q = $em->createQuery('select u from MyProject'Model'User u');
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
$entity = $row[0];
// do stuff with $entity here
// mark entity as processed
if (($i % $batchSize) == 0) {
$em->flush();
$em->clear();
gc_collect_cycles();
}
++$i;
}
无论如何,也许您应该重新考虑一下该脚本的体系结构,因为ORM不太适合处理大块数据。也许您可以处理原始SQL行?