在迭代期间取消设置数组值是否会节省内存?

时间:2011-01-12 21:16:38

标签: php foreach unset memory-optimization

这是一个简单的编程问题,源于我对PHP在foreach循环期间处理数组复制和取消设置的方式缺乏了解。就像这样,我有一个阵列从我想要改变的外部源格式来找我。一个简单的例子是:

$myData = array('Key1' => array('value1', 'value2'));

但我想要的是:

$myData = array([0] => array('MyKey' => array('Key1' => array('value1', 'value2'))));

所以我采用第一个$myData并将其格式化为第二个$myData。我的格式化算法完全没问题。我的问题在于找到一种节省内存的方法,因为这些数组可能会有点笨拙。因此,在我的foreach循环期间,我将当前数组值复制到新格式,然后我从原始数组中取消设置我正在使用的值。 E.g:

$formattedData = array();
foreach ($myData as $key => $val) {
    // do some formatting here, copy to $reformattedVal

    $formattedData[] = $reformattedVal;

    unset($myData[$key]);
}

这里对unset()的呼吁是个好主意吗?即,它是否节省了内存,因为我复制了数据而不再需要原始值?或者,PHP是否自动垃圾收集数据,因为我没有在任何后续代码中引用它?

代码运行正常,到目前为止,我的数据集的大小可以忽略不计,无法测试性能差异。我只是不知道自己是否会因为某些奇怪的错误或CPU点击而自行设置。

感谢您的任何见解 -sR

5 个答案:

答案 0 :(得分:4)

使用foreach运算符在&循环中使用对变量的引用。这样就可以避免在内存中复制数组foreach进行迭代。

编辑:正如Artefacto指出的那样,取消设置变量只会减少对原始变量的引用次数,因此保存的内存只是指针而不是变量的值。奇怪地使用引用实际上会增加总内存使用量,因为可能会将值复制到新的内存位置而不是被引用。

  

除非引用了数组,   foreach在一份副本上运作   指定的数组而不是数组   本身。 foreach有一些副作用   在数组指针上。不要依赖   期间或之后的数组指针   foreach而不重置它。

使用memory_get_usage()确定您正在使用的内存量。

对内存使用情况和分配here进行了很好的记录。

这是查看内存分配的有用测试代码 - 尝试取消注释注释行以查看不同方案中的总内存使用情况。

echo memory_get_usage() . PHP_EOL;
$test = $testCopy = array();
$i = 0;
while ($i++ < 100000) {
    $test[] = $i;
}
echo memory_get_usage() . PHP_EOL;
foreach ($test as $k => $v) {
//foreach ($test as $k => &$v) {
    $testCopy[$k] = $v;
    //unset($test[$k]);
}
echo memory_get_usage() . PHP_EOL;

答案 1 :(得分:3)

请记住rules of Optimization Club

  1. 优化俱乐部的第一条规则是,您不进行优化。
  2. 优化俱乐部的第二条规则是,如果不进行测量,则不进行优化。
  3. 如果您的应用运行速度比基础传输协议快,则优化已结束。
  4. 一次一个因素。
  5. 没有marketroids,没有marketroid时间表。
  6. 只要必要,测试就会继续进行。
  7. 如果这是您在优化俱乐部的第一个晚上,您必须编写测试用例。
  8. 规则#1和#2在这里特别相关。除非你知道你需要优化,除非你已经测量了优化的需要,否则不要这样做。添加未设置将增加运行时命中,并将使未来的程序员为什么要这样做。

    不管它。

答案 2 :(得分:3)

在循环中处理文本(xml)文件的行时,内存不足。对于任何有类似情况的人来说,这对我有用:

while($data = array_pop($xml_data)){
     //process $data
}

答案 3 :(得分:2)

如果在“格式化”中的任何时候你做了类似的事情:

$reformattedVal['a']['b'] = $myData[$key];

然后执行unset($myData[$key]);与内存无关,因为您只减少了变量的引用计数,该变量现在存在于两个位置($myData[$key]$reformattedVal['a']['b']内)。实际上,你保存了将变量索引到原始数组中的内存,但这几乎没有。

答案 4 :(得分:0)

除非您通过引用访问元素,否则unsetting将不会执行任何操作,因为您无法在迭代器中更改数组。

也就是说,修改你正在迭代的集合通常被认为是不好的做法 - 更好的方法是将源数组分解成更小的块(通过一次只加载一部分源数据)和处理这些,在你去的时候取消每个整个数组“块”。