在运行数千条记录时,PHP内存耗尽

时间:2011-01-01 01:53:53

标签: php memory

我在一组5,000个结果中运行以下代码。由于内存耗尽,它失败了。

foreach ($data as $key => $report) {
  $data[$key]['data'] = unserialize($report['serialized_values']);
}

我知道我可以提高内存限制,但我想在没有问题的情况下运行它。我不会永远保持记忆。


修改

$data采用以下格式:

[1] => Array
    (
        [0] => 127654619178790249
        [report_id] => 127654619178790249
        [1] => 1
        [user_id] => 1
        [2] => 2010-12-31 19:43:24
        [sent_on] => 2010-12-31 19:43:24
        [3] => 
        [fax_trans_id] => 
        [4] => 1234567890
        [fax_to_nums] => 1234567890
        [5] => ' long html string here',
        [html_content] => 'long html string here',
        [6] => 'serialization_string_here',
        [serialized_values] => 'serialization_string_here',
        [7] => 70
        [id] => 70
    )

7 个答案:

答案 0 :(得分:10)

除了for和foreach的问题之外,您还需要重新构建解决方案。您正在达到内存限制,因为您合法地使用了太多内存。每次反序列化数据库列的内容并将其存储在数组

$data[$key]['data']

PHP需要留出一大块内存来存储这些数据,以便以后可以访问。当你的阵列太大时,你就会失去记忆力。用简单的英语,你说的是PHP

  

获取所有5000行数据并将其存储在内存中,我稍后会对它们做些什么。

您需要考虑一种不同的方法来解决您的问题。以下是对这个问题的两个快速思考。

您无法将项目存储在内存中,只需在循环中执行您想要的任何操作,允许php根据需要丢弃项目

foreach ($data as $key => $report) {
    $object = unserialize($report['serialized_values']);        
    //do stuff with $object here
}

您也可以只存储来自反序列化对象的信息,而不是存储整个对象

foreach ($data as $key => $report) {
    $object             = unserialize($report['serialized_values']);        
    $data               = array();
    $data['foo']        = $object->foo;
    $data[$key]['data'] = $data;
}

长话短说:因为你实际上使用了太多内存,所以你达到了内存限制。这里没有神奇的解决方案。存储序列化数据并尝试将其全部加载到单个程序中是一种内存密集型方法,无论语言/平台如何。

答案 1 :(得分:3)

foreach会将所有5,000个结果加载到内存中。请参阅the docs中的众多投诉。使用for循环并根据需要访问每个结果。

答案 2 :(得分:1)

什么是$data,你从哪里得到它?如果它是一个文件,你不能一次fgets()一行解析,如果它是一个数据库,你不能一次处理一条记录(以等待关闭结果集的MySQL为代价) 。我认为你应该重新考虑将整个$data一次加载到内存中,然后循环遍历它。

答案 3 :(得分:0)

试试这种方式

foreach ($data as $key => &$report) {
}

这将分配引用而不是复制值。

答案 4 :(得分:0)

这实际上是许多网站将结果划分为页面的原因。

假设我有5000个结果(比如用户,为了简化),我有一个页面应该显示所有这5000个结果。我将这5000个结果分成每页500个,这样一个页面1显示1 - 500,页面2显示501 - 1000,页面3显示1001 - 1500,依此类推。这样就可以节省内存。

如果您确实需要在一个页面中显示所有5000个结果,则确实需要增加内存限制。或者改为使用循环。

答案 5 :(得分:0)

我不确定,但您可以使用:

  • gzip($ data set)将数据压缩到安全内存并动态放气。
  • 限制(数据)设置。
  • 创建类似系统的缓存。如果使用太多内存,则从缓存中删除最近最少使用的(LRU)数据。

答案 6 :(得分:0)

我认为这些错误尚未结束:

"在循环内反序列化相同的序列化对象时,总内存 消费增加每两次迭代"