首页 文章

strripos允许的内存大小为134217728字节耗尽(试图分配58887728字节)

提问于
浏览
2

好吧,我得到了这个代码:

function importXML($filename){
    if(file($filename)) $xml_file = file($filename);
    else umar(97);

    $content = substr($xml_file[1], strpos($xml_file[1], "<office:spreadsheet>"), strpos($xml_file[1], "</office:spreadsheet>") - strpos($xml_file[1], "<office:spreadsheet>"));
    $arr = array();
    $arr2 = array();
    $check = strripos($content, "</table:table-row>") + 18;
    $offset = 0;

    while($offset != $check){
        $start2 = strpos($content, "<table:table-row ", $offset);
        $end2 = strpos($content, "</table:table-row>", $offset);
        $offset = $end2 + 18;


        array_push($arr2, $start2, $end2);
        array_push($arr, substr($content, $start2, $end2-$start2));
    }

    return json_encode($arr);


}

而这一行

$check = strripos($content, "</table:table-row>") + 18;

返回错误

允许的内存大小为134217728字节耗尽(尝试分配58887728字节)

我正在使用58893135字节文件 .

在php.ini中设置

memory_limit = 128M

所以我想知道为什么我会得到这个错误,我怎么能摆脱它 .

3 回答

  • 1

    让我们稍微分解一下:

    if(file($filename)) $xml_file = file($filename);
    

    这里 $xml_file 将占用58MB . 更不用说你正在读两次文件 . 你应该改为:

    if (file_exists($filename)) $xml_file = file($filename);
    

    下一位:

    $content = substr($xml_file[1], 
               strpos($xml_file[1], "<office:spreadsheet>"), 
               strpos($xml_file[1], "</office:spreadsheet>") - 
                   strpos($xml_file[1], "<office:spreadsheet>")
             );
    

    在这里,您需要在一个大文件中查找 <office:spreadsheet> 两次,然后将子字符串存储在 $content 中,这也将占用大约58MB . 您可以在此时执行: $xml_file = null; 如果您不需要它,则删除对它的引用,即

    $spreadSheetStart = strpos($xml_file[1], "<office:spreadsheet>");
    $spreadSheetLen = strpos($xml_file[1], "</office:spreadsheet>") - $spreadSheetStart;
    $content = substr($xml_file[1], $spreadSheetStart, $spreadSheetLen);
    $xml_file = null;
    

    现在最后你有一个大小约为58MB的数组,你需要把它变成一个相同大小的JSON,同时仍然在内存中有 $content ,这意味着你需要170MB . 你可以再做一次:

    $content = null; //unset($content); would also work. 
    return json_encode($arr);
    

    关于PHP和字符串以及数组,您需要了解的主要事情是,PHP数组和字符串的行为类似于原始类型,这意味着它们总是按值传递 . 例:

    $a = "Test"; 
    $b = $a;
    $b .= " again";
    echo $a.PHP_EOL.$b.PHP_EOL;
    

    这打印:

    再次进行测试

    这表示 $b$a 的副本,而不是对同一内存位置的引用 . 副本意味着您通过执行 $b = $a; 实际上使代码的内存需求翻了一番

    数组和所有其他基元(数组,整数,布尔值,浮点数)也是如此 .

  • 1

    正如apokryfos在评论中提到的,我们不应该使用类似的东西:

    while(1)
    

    要么

    while(true)
    

    要么

    while(1===1)
    

    或类似的东西 .

    虽然如果你必须使用它然后在那种情况下,我相信正在发生的是你的while循环不知何故永远不会进入你的break语句,这意味着你的条件: ($offset == $check) 永远不会成真 .

    作为验证,尝试在之前启动计数器: $count = 1; 在while结束时增加它并且当它设为50时强加一个中断条件:

    while(true){
        //your code
        if($count === 50){
            break;
         }
         $count++;
    }
    

    现在,如果问题得到解决,那么肯定是因为你的 if 破坏条件永远不会变得真实..想到所有方面并添加更多条件 .

    如果没有,那么我相信你的应用需要比你提供的更多的内存 . 现在我 HIGHLY DISCOURAGE 这个方法,但直到你发现真正的问题,你可以添加:

    ini_set('memory_limit','256M');
    

    在代码的开头 .

    但我再次提到,你的代码中存在问题,增加内存限制不是解决方案,但它会给你机会找到真正的问题 .

  • 0

    试试这个 !你可以添加这一行:

    ini_set(”memory_limit","80M");
    

    之前

    $check = strripos($content, "</table:table-row>") + 18;
    

相关问题