【问题标题】:Out of memory error in phpphp内存不足错误
【发布时间】:2012-10-25 03:05:22
【问题描述】:

我正在使用 php 5.2.5 并从命令行执行脚本。在这个脚本中,我正在处理从 db 获取的数据。要从 db 获取数据,我使用 Zend Adapter。 我注意到调用后内存增加(262144 字节) "fetchAll($sql,$data,Zend_Db::FETCH_ASSOC)"

因此最终导致内存不足。 为了测试,我只是执行了“fetchAll”,甚至没有将它返回的数据存储在任何变量中。但是我仍然看到没有回收的内存增加。

  • Zend FetchAll 方法是否存在内存泄漏问题?
  • 为什么内存会增加 262144 或 262144 的倍数?
  • 内存增加是随机发生的,并非在所有 fetchAll 调用中都发生,为什么会这样?

我已经尝试使用 memory_get_usage() 来确定内存泄漏的原因,但是由于代码很大,因此需要很长时间,有什么方法可以获取内存中所有对象的详细信息,以便我可以更好地调试问题吗?

sql是:-

select b.Id as Id,b.Lang 
from groups g 
left join table1 b on b.Group_Id = g.Id 
left join table2 bs on bs.Id = b.Id 
where g.Id = ? and b.Lang = ?

【问题讨论】:

  • 如果您还包含 sql 命令,则最好。因为这可能是一个问题(例如,您在不使用限制的情况下连接多个表,以便每一行都与每一行连接)。
  • 该 sql 是“从组 g 中选择 b.Id 作为 Id,b.Lang 在 b.Group_Id = g.Id left join table2 bs on bs.Id = b.Id where g.Id = ? 和 b.Lang = ?"。请你能更好地解释一下为什么内存使用会因为sql语句问题而增加。
  • 对于泄漏问题本身,我认为那里的答案很好。从我看到的 sql 不会导致一般问题(因为它限制了哪些行与哪一行相关联)。似乎真的是表本身中有太多数据行或内存泄漏。正如你提到的,代码是巨大的。您是否在它们过时后取消设置存储输入的变量? (否则他们仍然保留内存)
  • 我假设您希望取消设置的变量是 $result 在这一行 "$result = fetchAll($sql,$data,Zend_Db::FETCH_ASSOC);"我没有取消设置变量,因为变量在方法的范围内,所以我期望它不应该保留在内存中?即使在方法执行完成之后,是否有可能存在方法范围内的变量?请你也可以分享任何关于内存泄漏问题的好链接。
  • 你可以用$this->fetchRow($where);代替fetchAll()

标签: php mysql zend-framework memory fetchall


【解决方案1】:

要一次返回所有结果,它们必须存储在内存中的数组中。即使您没有将该结果分配给任何变量,fetchAll 在内部仍然必须构建该数组。如果有太多的结果一次存储在内存中,你就会耗尽内存;很简单。

至于为什么不总是回收内存:可能存在内存泄漏,但更可能的是 PHP 的垃圾收集器根本没有立即启动以回收内存。您可以尝试使用gc_collect_cycles 强制执行 gc 循环来确认。

【讨论】:

  • 因为我在 5.2.5 上,所以我不能使用 gc_collect_cycles。没有返回太多结果以使其内存不足。每次迭代返回的结果数量几乎相同。我同意内存可能不会立即回收但应该在 php 达到其内存限制时被回收的事实。但内存只是在每几次迭代后不断增加。
  • 我对 Zend 没有太多经验,但我确实使用过 Zend_Search_Lucene,之前它也喜欢耗尽内存。它可能只是编码错误...... :) 简单的答案是:如果您有内存不足错误,那么您在内存中存储了太多。干净利落。也许 Zend 没有正确释放结果,或者它在内部缓存数据,或者其他什么。
【解决方案2】:

为了测试,我只是执行了“fetchAll”,甚至没有存储数据

但是您已经存储了 2 个数据副本。大多数数据库客户端将维护服务器返回的数据缓冲区(在 mysql 的情况下,它具有完整的数据集)。当您调用 fetchAll() 时,整个数据集将被检索到缓冲区(如果它不存在) 并且 然后将其映射到 PHP 数组。

你有明确的 closeCursor 调用吗?

【讨论】:

  • 我没有明确地调用它,假设 zend 框架会处理它。
【解决方案3】:

您可以逐行获取结果而不将其加载到内存中:

   /**
    * @var $select \Zend_Db_Select
    **/
    if ($stmt = $select->query()) {
        while ($row = $stmt->fetch()) { //... }
    }

【讨论】:

    猜你喜欢
    • 2014-06-01
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    相关资源
    最近更新 更多