数组 - 在PHP中的内存不足

时间:2017-10-02 19:52:09

标签: php arrays

我有一大堆关联数组。每个关联数组由大约15个不同类型的键组成(字符串,整数,浮点数) - 下面的小例子:

$array = [
    [
      "key1" => "string",
      "key2" => 10,
      "key3" => 4.05
    ],       
    [
      "key1" => "string2",
      "key2" => 20,
      "key3" => 1.05
    ],       
   ...
];

现在我想迭代这个数组并添加一些像

这样的键
$map = array_map(function (array $item) {            
       $item['key4'] = 1;
       $item['key5'] = 1;
       $item['key6'] = 1;
       return $item;
   }, $array);

问题:对于包含大量关联数组的数组,添加新键会使达到内存限制并终止脚本。你有任何解决方案吗?

2 个答案:

答案 0 :(得分:2)

您可以对数据进行分页,对数组进行分块以处理较小的数据,甚至可以增加memory_limit,但我们假设您有一个大数组,但不能这样做。

让我们玩一个1 000 000长阵列并尝试不同的解决方案。我会把内存消耗和放大从笔记本电脑计算时间测量值

当前解决方案(857MB / 640ms)

for ($i=0; $i< 1000000; $i++){
    $array[$i] = [
        "key" => 'value',
        "key2" => $i,
        "key3" => $i / 3
    ];
}

$map = array_map(function (array $item) {
    $item['key4'] = 1;
    $item['key5'] = 1;
    $item['key6'] = 1;
    return $item;
}, $array);

使用这段代码,我的笔记本电脑的内存消耗 857MB,计算时间为640ms

在您的示例中,您要从$map创建一个全新的$array变量。这意味着您正在内存中制作数组的新副本。

使用references(480MB / 220ms)

$array = [];
for ($i=0; $i< 1000000; $i++){
    $array[$i] = [
        "key" => 'value',
        "key2" => $i,
        "key3" => $i / 3
    ];
}

foreach ($array as &$item) {
    $item['key4'] = 1;
    $item['key5'] = 1;
    $item['key6'] = 1;
}

使用&$item我们要求PHP通过引用让我们访问变量,这意味着我们直接在内存中修改数据而不创建它的新副本。

这就是为什么这个脚本消耗的内存和内存要少得多。计算时间。

使用类(223MB / 95ms)

在幕后,PHP使用C数据结构来管理内存中的数据。对于PHP来说,类比数组更容易预测且更容易优化。很好地解释了here

class TestClass {
    public $key1,   $key2, $key3,   $key4, $key5, $key6;
}

$array = [];
for ($i=0; $i< 1000000; $i++){
    $array[$i] = new TestClass();
    $array[$i]->key1 = 'value';
    $array[$i]->key2 = $i;
    $array[$i]->key3 = $i / 3;
}

foreach ($array as $item) {
    $item->key4 = 1;
    $item->key5 = 1;
    $item->key6 = 1;
}

你可以看到内存消耗&amp;迭代的时间要低得多。这是因为PHP不需要修改内存中数据的结构:对象的每个字段都准备好接收数据。

但要小心,如果添加一个未在类中声明的字段(例如$item->newKey = 1:动态声明newKey):将无法再进行内存优化,您将跳转到620mb内存使用量&amp; 280ms计算)

如果你想更进一步,不怕头痛,请看一下Standard PHP Library(SPL):你会发现很多优化的数据结构解决方案(固定阵列,迭代器等等)。 ..)

PS:禁用Xdebug的基准测试

答案 1 :(得分:-1)

如果您使用引用,您应该能够节省一些内存。这将删除在后台发生的写入操作的许多副本。在一个小测试案例中。我能够将内存减少30%-40%(取决于PHP版本)。如果您使用PHP5,您还可以从升级到PHP7中获益。显然我无法预测其中一个或两个是否能够保存足够的内存。 测试用例(只需在地图或步行之前删除$(".hideme_sometimes").hide();):

/*