PHP内存调试

标签 php symfony doctrine-orm xdebug kcachegrind

对于我的项目,我需要导入一个非常大的文本文件(~ 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);

我尝试过的事情,但没有任何帮助:

  1. 将第二个参数添加到fgets
  2. 增加内存限制
  3. 取消设置变量

最佳答案

增加内存限制是不够的。当导入这样的文件时,您可以缓冲读取。

$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/

相关文章:

php - 如果不存在不同的结果,则插入到表中

php - 如何在 PHP 和 MySQL 中同时将数据插入到两个或多个表中?

php - 向首次访问者显示欢迎信息

symfony - 在链配置的命名空间中找不到另一个 "The class ' X'

php - 有没有办法像在 javascript 中一样向 php 类添加方法?

php - 在 Symfony2 中干净地扩展 Propel 模型的策略?

symfony - 如何将嵌入式的YouTube视频记录添加到symfony应用程序

symfony - monolog.logger.db 服务已被删除

mongodb - 存储库查询 :searching inside an array

php - Symfony 2.0实体表单字段不保存