总是在同一行上内存耗尽


Running out of memory always on the same line

首先,我不是在寻找一个回答说"检查你的PHP内存限制"或"你需要添加更多的内存"或这些东西…我在一台专用的机器上,有8GB的ram;512MB是内存限制。我总是在一行上得到内存不足的错误:

澄清一下:这部分代码属于Joomla!CMS .

function get($id, $group, $checkTime){
    $data = false;
    $path = $this->_getFilePath($id, $group);
    $this->_setExpire($id, $group);
    if (file_exists($path)) {
        $data = file_get_contents($path);
        if($data) {
            // Remove the initial die() statement
            $data   = preg_replace('/^.*'n/', '', $data); // Out of memory here
        }
    }
    return $data;
}

这是Joomla缓存的一部分…这个函数读取缓存文件,并删除第一行阻止对文件的直接访问,并返回其余的数据。

可以看到,该行使用preg_replace来删除缓存文件中的第一行,它总是:

<?php die("Access Denied"); ?>

我的问题是,在我看来,作为一个简单的过程(从文件内容中删除第一行),如果初始$data很大,它会消耗大量内存吗?如果是这样,解决这个问题的最佳方法是什么?我不介意缓存文件没有die()行,我可以采取安全措施并阻止对缓存文件的直接访问。

我错了吗?

正如帖子所建议的那样,regex似乎创造了更多的问题而不是解决它们。我试过:

echo memory_get_usage() . "'n";

在正则表达式之后,然后使用substr()尝试相同的语句。在内存使用方面差别很小。几乎没有。

感谢你的贡献,我仍在努力找出发生这种情况的原因。

使用substr避免占用大量内存的preg_replace(),如下所示:

$data = substr($data, strpos($data, '?>') + 3);

作为一般建议,如果您可以使用其他字符串/数组函数来完成相同的任务,则不要使用正则表达式,因为正则表达式函数比核心字符串/数组函数更慢且消耗更多内存。

这在PHP文档中也有明确的警告,参见一些例子:

http://www.php.net/manual/en/function.preg-match.php refsect1-function.preg-match-noteshttp://www.php.net/manual/en/function.preg-split.php refsect1-function.preg-split-notes

不要使用字符串函数来替换大字符串中的内容。您可以循环遍历文件的行,并在找到所需内容后中断。查看PHP文档:

http://php.net/manual/en/function.fgets.php

基本上就是@ buckley刚才说的:p

如果您只想删除文件的第一行并返回其余部分,您应该使用file:

$lines = file($path);
array_shift($lines);
$data = implode("'n", $lines);

不要使用一次性获取整个文件的file_get_contents(),因为它太大而无法在上面运行regexp,您应该将fopen()fgets()结合使用(http://php.net/fgets)。这个函数逐行获取文件。

然后可以选择在特定行上执行regexp。或者直接跳过整行。

所以不用:

$data = file_get_contents($path);
if($data) {
    // Remove the initial die() statement
    $data   = preg_replace('/^.*'n/', '', $data); // Out of memory here
}

试试这个:

$fileHandler = fopen($path,'r');
$lineNumber = 0;
while (($line = fgets($fileHandler)) !== false) {
    if($lineNumber++ != 0) { // Skip the initial die() statement
        $data .= $line; // or maybe echo out $line directly so $data doesn't take up too much memory as well.
    }
}

我建议你在文件中使用这个,包括缓存的文件:

define('INCLUDESALLOW', 1);

和将包含的文件:

if( !defined('INCLUDESALLOW') ) die("Access Denied");

那就用include代替file_get_contents。这将在包含的PHP代码中运行,但不能100%确定这是否是您需要的。

有时会使用比php分配的8 MB更多的内存。如果无法通过提高代码效率来使用更少的内存,则可能必须增加可用内存。这可以通过两种方式实现。

限制可以在php.ini中设置为全局默认值:

memory_limit = 32M

或者你可以在脚本中重写它,像这样:

<?php
ini_set('memory_limit', '64M');
...

有关PHP内存限制的更多信息,请参见This SO问题或ini.memory-limit.