以下代码在具有约1,000,000行的表上迭代。建议我使用学说的iterateresult()方法来避免记忆问题(文档):
$batchSize = 1000;
$i = 0;
$q = $em->createQuery('SELECT i from MyBundle:Items i WHERE i.imgSize IS NULL');
$results = array();
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
$results[]=$row[0];
$em->detach($row[0]);
if (($i % $batchSize) === 0) {
$em->clear(); // allegedly detaches all objects from Doctrine!
$this->chunkedWhereCallback($results);
}
++$i;
}
即使我将批处理大小设置为1,上面的代码超出了允许的内存。如果我更改查询以读取 SELECT i.id, i.img FROM MyBundle:Items i WHERE i.imgSize IS NULL
,则不存在内存错误,但是我的$行阵列没有[0]键,例如:<:
array(1) {
[5926] =>
array(2) {
'id' =>
int(12794)
'img' =>
string(57) "http://some/url/1203/104962420.jpg"
}
}
有人可以告诉我我在这里缺少什么吗?Laravel的雄辩处理此操作很好,但我想将代码移植到Doctrine/Symfony2。我已经尝试将PHP内存限制设置为1024m,这应该远远足够,并且比服务器上的可用。
Memory error is Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 32 bytes) in /Users/mre/Sites/ site/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php on line 699
我也遇到了同样的问题,我不确定这是学说的问题,这似乎是PHP本身的问题。
无论如何,我发现的解决方案是强迫PHP的垃圾收集到这样的情况:
$batchSize = 1000;
$i = 0;
$q = $em->createQuery('SELECT i from MyBundle:Items i WHERE i.imgSize IS NULL');
$results = array();
$iterableResult = $q->iterate();
while (($row = $iterableResult->next()) !== false) {
$results[]=$row[0];
$em->detach($row[0]);
if (($i % $batchSize) === 0) {
$em->clear(); // allegedly detaches all objects from Doctrine!
// Force PHP's GC
gc_collect_cycles();
$this->chunkedWhereCallback($results);
}
++$i;
}
呼叫gc_collect_cycles
应释放内存并防止可用内存的耗尽。