对于我的项目,我需要导入一个非常大的文本文件(~ 950MB)。我在我的项目中使用 Symfony2 和 Doctrine 2。
我的问题是我收到如下错误:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 24 bytes)
如果我将内存限制增加到 1GB,甚至会出现该错误。
我尝试使用 XDebug 和 KCacheGrind (作为 PHPEdit 的一部分)来分析问题,但我并不真正理解这些值:(
我正在寻找一种工具或方法(快速且简单,因为我没有太多时间)来找出为什么分配内存而不再次释放内存。
编辑
要清除这里的一些内容是我的代码:
$handle = fopen($geonameBasePath . 'allCountries.txt','r');
$i = 0;
$batchSize = 100;
if($handle) {
while (($buffer = fgets($handle,16384)) !== false) {
if( $buffer[0] == '#') //skip comments
continue;
//split parts
$parts = explode("\t",$buffer);
if( $parts[6] != 'P')
continue;
if( $i%$batchSize == 0 ) {
echo 'Flush & Clear' . PHP_EOL;
$em->flush();
$em->clear();
}
$entity = $em->getRepository('MyApplicationBundle:City')->findOneByGeonameId( $parts[0] );
if( $entity !== null) {
$i++;
continue;
}
//create city object
$city = new City();
$city->setGeonameId( $parts[0] );
$city->setName( $parts[1] );
$city->setInternationalName( $parts[2] );
$city->setLatitude($parts[4] );
$city->setLongitude( $parts[5] );
$city->setCountry( $em->getRepository('MyApplicationBundle:Country')->findOneByIsoCode( $parts[8] ) );
$em->persist($city);
unset($city);
unset($entity);
unset($parts);
unset($buffer);
echo $i . PHP_EOL;
$i++;
}
}
fclose($handle);
我尝试过的事情,但没有任何帮助:
- 将第二个参数添加到fgets
- 增加内存限制
- 取消设置变量
最佳答案
增加内存限制是不够的。当导入这样的文件时,您可以缓冲读取。
$f = fopen('yourfile');
while ($data = fread($f, '4096') != 0) {
// Do your stuff using the read $data
}
fclose($f);
更新:
使用 ORM 时,您必须了解,在刷新调用之前,实际上没有任何内容插入到数据库中。这意味着所有这些对象都由标记为“要插入”的 ORM 存储。只有当进行flush调用时,ORM才会检查集合并开始插入。
解决方案 1:经常冲洗。并且清晰。
解决方案 2:不要使用 ORM。使用简单的 SQL 命令。它们将比对象 + ORM 解决方案占用更少的内存。
关于PHP内存调试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9054520/