【问题标题】:Modifying array values in php Memory exhaust修改php内存耗尽中的数组值
【发布时间】:2017-04-20 06:10:20
【问题描述】:

我有一段php代码如下:

foreach($collection as $key => $item) {
  $collection[$key]['column'] = 'test';
  $item['column'] = 'test';
}

当集合数组的行数超过 30,000 时,我收到此错误 PHP 致命错误:允许的内存大小为 134217728 字节已用尽(尝试分配 89 字节)。

如果我删除 $collection[$key]['column'] 行,forloop 可以成功完成。

我无法理解的是,第 2 行和第 3 行不是基本相同的吗?它们都在更改 $collection 数组中的同一个项目。

我在这里错过了什么?

【问题讨论】:

  • 实际上修改 $item 会创建一个副本并修改它,而不是 $collection(请参阅写时复制)。所以可能 php 正在垃圾收集那些未使用的 $item ,因此它不会像在第 2 行那样添加到集合中那样耗尽你的内存。我怀疑你是否要将 $item 更改为 &$item (导致更改为 $ item to change $collection) 在第 1 行注释掉第 2 行时会遇到同样的问题。

标签: php


【解决方案1】:

要回答您的问题,让我们先快速浏览一下foreach docs

在每次迭代中,将当前元素的值分配给 $value 并且内部数组指针前移 1(依此类推 下一次迭代,您将看到下一个元素)。

首先让我们先回答你的第一个问题,然后再回答你的第二个问题。

我无法理解的是基本上不是第 2 行和第 3 行 一样吗?

实际上它们并不相同,举个简单的例子:

$array = ['a', 'a', 'a', 'a'];

foreach ($array as $key => $value) {
    $value = 'b';
}

print_r($array);
// Output : Array ( [0] => a [1] => a [2] => a [3] => a )

在第二种情况下:

$array = ['a', 'a', 'a', 'a'];

foreach ($array as $key => $value) {
    $array[$key] = 'b';
}

print_r($array);
// Output : Array ( [0] => b [1] => b [2] => b [3] => b )

所以,很明显,在您的第一种情况下,您可以说修改了一些复制值或赋值,并没有触及实际值。

所以我们可以说 -so to speak- 作为 php 函数的 foreach 有它自己的上下文,例如:

foreach ($array as $key => $value) {
    // $value variable will be only visible here
    // within the foreach context
}
echo $value; // will output Undefined variable

它们都在更改 $collection 数组中的同一个项目。

您可以说 - 或假设- 您已将变量按值传递给 foreach,因此 php -如 foreach 文档中所述- 修改了您的数组元素,而不是实际值。

在第二个示例中,您修改了数组 $array 的实际值,而不仅仅是它的副本。

在我的示例上下文中,要修改您的数组,您需要将变量传递给 foreach by reference 以便能够直接编辑您的数组值,例如:

$array = ['a', 'a', 'a', 'a'];

foreach ($array as $key => &$value) {
//                         ^
    $value = 'b';
}

print_r($array);
// Output : Array ( [0] => b [1] => b [2] => b [3] => b )

让我们转到您的另一个问题:

如果我删除 $collection[$key]['column'] 行,forloop 可以 成功完成。

发生这种情况是因为如上所述,您将变量按值传递给 foreach,因此对于您的 30,000 数组的每次迭代,php 将执行三个操作:-

1) 将数组的每个元素复制到内存中的另一个位置
2) 更新这个复制的元素
3) 更新你的集合数组

我认为这比你的最大内存限制占用更多的内存。

所以,正如他的评论中提到的Christopherforeach doc page 中提到的那样:

为了能够在循环内直接修改数组元素 在 $value 之前加上 &。在这种情况下,该值将由 参考。

通过引用传递值可能会减少脚本的内存使用量。

【讨论】:

    【解决方案2】:

    试试这个:

    ini_set('memory_limit', '-1');
    

    不建议这样做,但在您的情况下需要这样做。这将覆盖默认的 PHP 内存限制。

    【讨论】:

    • 操作员的问题是关于分配的差异,即一个会导致内存问题而不是另一个,而不是完全避免内存问题......
    • 但标题表明内存已耗尽。
    • 存在内存泄漏,要知道为什么该人需要发布整个代码。
    • 是的,但这只是标题。提出的问题在帖子的结尾处。
    • 内存耗尽不一定意味着内存泄漏。作者指出,将数据添加到已经很大的数据集时会出现这种情况。
    猜你喜欢
    • 1970-01-01
    • 2015-10-01
    • 2014-09-08
    • 2013-07-06
    • 2014-06-28
    • 2011-04-20
    • 1970-01-01
    • 2011-04-02
    相关资源
    最近更新 更多