当前位置: 首页 > 知识库问答 >
问题:

允许的内存大小在PHP for循环中耗尽

狄晟睿
2023-03-14

当我试图在PHP中操作大量数组并将结果作为HTTP POST请求的响应返回时,我遇到了一个致命错误:

允许内存大小536870912字节已用尽

我已经尝试设置ini_set('memory_limit','-1')以查看是否得到结果,但没有得到任何类型的响应。邮递员在我试图发出邮寄请求时总是崩溃。

数组的起始结构是这个。机身尺寸约为25mb。主阵列包含大约22k个具有此结构的阵列,我刚刚包括2个:

Array
(
    [0] => Array
        (
            [id] => 14
            [isActive] => 1
            [personId] => 0023fff16d353d16a052a267811af53bc8bd42f51f2266a2904ca41db19dfd32_0
            [gender] => m
            [age] => 69
            [linedata_0] => 2018-03-01 17:15:18, 155.59, 294.076; 2018-03-01 17:16:04, 502.968, 249.947; 2018-03-01 17:16:44, 276.837, 270.593; 2018-03-01 17:17:28, 431.68, 371.14; 2018-03-01 17:17:34, 851.622, 355.915
        )

    [1] => Array
        (
            [id] => 180
            [isActive] => 1
            [personId] => 02659982ae8286409cc5bb283089871b62f2bafbbad517941d64e77ecf2b62b1_0
            [gender] => m
            [age] => 69
            [linedata_0] => 2018-03-01 13:20:05, 155.599, 293.841; 2018-03-01 13:20:48, 495.468, 249.582; 2018-03-01 13:21:28, 258.791, 260.748; 2018-03-01 13:23:20, 859.061, 352.237; 2018-03-01 13:23:32, 56.1404, 269.858
        )
)

下面的php部分用于操作数组,以便通过爆炸每个用户的时间戳和坐标来获得预期的最终结果:

$final_result = [];

foreach($query_result as $row)
{
    $line_datas =explode(";",$row["linedata_0"]);
    $linedata = [];
    $final = [];
    $d = [];

    for($s =0; $s < count($line_datas); $s++){
        $line_data = explode(",",$line_datas[$s]);
        $d["timestamp"] = utf8_encode($line_data[0]);
        $d["x"]= utf8_encode($line_data[1]);
        $d["y"] = utf8_encode($line_data[2]);

        array_push($linedata,$d);
    }

    $final["id"]= $row["id"];
    $final["isActive"]= $row["isActive"];
    $final["personId"]= utf8_encode($row["personId"]);
    $final["name"] = NULL;
    $final["gender"] = utf8_encode($row["gender"]);
    $final["age"] = utf8_encode($row["age"]);
    $final["linedata"]=$linedata;

    array_push($final_result, $final);
}

return $final_result;

在我看来,没有无限循环或不良实践可以证明内存问题是合理的。唯一真正的问题可能是需要操作的数组的大小。

有什么建议吗?

共有3个答案

施默
2023-03-14

在这种情况下,使用大数据是不好的做法。

想象一下:你有一个变量$a,它包含22k个数组,你开始形成第二个变量$b,它也包含22k个数组。

因此,在脚本的末尾,u将有2个变量和22k数组。

为了避免这些问题,您应该分批获取数据。例如,一个循环中有500行。

    function findRows($offset = 0, &$final_result = []) {
        $sql = 'SELECT * FROM my_table LIMIT ' . $offset . ', 500';
        //your code to find rows

        if ($query_result) {
            $offset = $offset + 500;

            foreach($query_result as $row) {
                //your another code
                array_push($final_result, $final);
            }
            findRows($offset, $final_result);
        }

        return $final_result;
    }

    return findRows();
夏理
2023-03-14

这个答案是一个如何在代码中实现缓冲区(内存中的有限数组)的示例,当它被填满时,将其内容刷新到磁盘上,最后您将在磁盘上找到一个JSON格式的巨大数组。我在与您类似的情况下使用了这种方法,并在“内存使用”方面获得了很好的结果,但正如我在评论中告诉您的,您需要重新思考为什么首先需要那个巨大的数组,如果有办法避免它,就使用它。

使用此函数将节省$final\u result数组使用的内存,并将其替换为$final\u result string buffer,但我们控制它的内存使用。但是,$query\u结果数组仍将占用它所需的内存。

请注意,您需要根据需要更改函数,因为我使用了代码中未定义的变量。

/**
 * proccess the HUGE array and save it to disk in json format [element,element]
 * 
 * @param string $fileName absulote file name path you want to save the proccessed array in
 * @return int processed elements count
 */
function buildMyArrayInFile($fileName)
{
    $flushCheckPoint = 100;// set the buffer size as needed, depending on the size of PHP allowed memory and average element size
    $processedElements = 0;
    $final_result = "[";

    file_put_contents($fileName, "");//prepare the file and erase anything in it

    foreach($query_result as $row)
    {
        $line_datas =explode(";",$row["linedata_0"]);
        $linedata = [];
        $final = [];
        $d = [];

        for($s =0; $s < count($line_datas); $s++){
            $line_data = explode(",",$line_datas[$s]);
            $d["timestamp"] = utf8_encode($line_data[0]);
            $d["x"]= utf8_encode($line_data[1]);
            $d["y"] = utf8_encode($line_data[2]);

            array_push($linedata,$d);
        }

        $final["id"]= $row["id"];
        $final["isActive"]= $row["isActive"];
        $final["personId"]= utf8_encode($row["personId"]);
        $final["name"] = NULL;
        $final["gender"] = utf8_encode($row["gender"]);
        $final["age"] = utf8_encode($row["age"]);
        $final["linedata"]=$linedata;


        $final_result .= json_encode($final) . ",";
        $processedElements ++;
        if($processedElements % $flushCheckPoint === 0){
            //the array has reached the limit, flush the array to disk
            file_put_contents($fileName, $final_result, FILE_APPEND);
            $final_result = "";
        }

    }

    $final_result = rtrim($final_result, ",");//trim the last comma
    $final_result .= "]";
    //flush the remaning data in $final_result
    file_put_contents($fileName, $final_result, FILE_APPEND);

    return $processedElements;

}

这是用于测试的函数的另一个简单版本

// test
var_dump(buildMyArrayInFile2("/home/myuser/myArray.json"));
// outputs int(7)



function buildMyArrayInFile2($fileName)
{
    $flushCheckPoint = 2;// set the buffer size as needed, depending on the size of PHP allowed memory and average element size
    $processedElements = 0;
    $final_result = "[";

    file_put_contents($fileName, "");//prepare the file and erase anything in it

    $test_result = [1,2,3,4,"wee","hello\nworld",5];
    foreach($test_result as $row)
    {
        $final_result .= json_encode($row) . ",";
        $processedElements ++;
        if($processedElements % $flushCheckPoint === 0){
            //the array has reached the limit, flush the array to disk
            file_put_contents($fileName, $final_result, FILE_APPEND);
            $final_result = "";
        }

    }

    $final_result = rtrim($final_result, ",");//trim the last comma
    $final_result .= "]";
    //flush the remaning data in $final_result
    file_put_contents($fileName, $final_result, FILE_APPEND);

    return $processedElements;
}
曾沛
2023-03-14

您正在将大量数据收集到数组中,然后才返回它。

相反,如果您收集单个“$final”项,并在foreach循环中产生它,而不是将它放入一个不断增大的变量中,那么您仍然能够围绕函数调用进行foreach。

下面是一个简单的例子,其中$i作为一个示例返回值,而不是您收集的数据的$最终数组。

<?php
function count_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

$generator = count_one_to_three();
foreach ($generator as $value) {  // you can also foreach(count_one_to_three() as $value)
    echo "$value\n";
}

PHP中的“收益率”信息

 类似资料:
  • 当我试图在PHP中操作大量数组并将结果作为HTTP POST请求的响应返回时,我遇到了一个致命错误: 允许内存大小536870912字节已用尽 我已经尝试设置以查看是否得到结果,但没有得到任何类型的响应。邮递员在我试图发出邮寄请求时总是崩溃。 数组的起始结构是这个。机身尺寸约为25mb。主阵列包含大约22k个具有此结构的阵列,我刚刚包括2个: 下面的php部分用于操作数组,以便通过爆炸每个用户的时

  • 我有一个网页,可以将图像上传到我的API Laravel项目。它一直工作到我上传大小巨大或等于2mb的图像,并在nginx 500错误中运行: 我在stack overflow和google上读到了大量相同的问题,但似乎没有任何效果。 仔细阅读错误消息,我可以理解,从我的PHP配置,该网站可以采取134217728字节的内存,但它无法尝试分配73728字节:它有任何意义吗?它只在允许的最大128m

  • 我正在尝试运行artisan make:controller。 我有一个问题: 我试图增加

  • 在同一个系统中,我可以调用数据库,没有问题,但在某些情况下(与最大的表),我得到 “PHP致命错误:第311行的/home/forge/sximo.sp-marketing.com/vendor/laravel/framework/src/light/Database/Connection.PHP中允许的内存大小为536870912字节(尝试分配32字节) 我调试了代码,问题是一个基本查询: 当我

  • 我有以下代码: 不同的文件: 由于我编写了Mail()函数,因此出现以下错误: 致命错误:允许的内存大小134217728字节已用尽(尝试分配65488字节)

  • 我正在使用phpspreadsheet,我想修改一个有4张表的xlsx文件。我只想在2张表中插入数据,但我想将所有4张表复制到新的xlsx文件中。当我这样做时,我会得到以下错误: 编辑:我已经尝试用下面的代码复制我不需要编辑的工作表: 但现在我得到另一个错误: 致命错误:未捕获错误:调用C:\xampp\htdocs\offerconfigurator\vendor\phpoffice\phpsp