4

首先,我不是在寻找“检查您的 PHP 内存限制”或“您需要添加更多内存”之类的答案......我在一台专用机器上,有 8GB 的​​ RAMS;其中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() 行的缓存文件,我可以采取安全措施并阻止对缓存文件的直接访问。

我错了吗?

更新

正如帖子所建议的那样,正则表达式似乎产生的问题多于解决问题。我试过了:

echo memory_get_usage() . "\n";

在正则表达式之后然后尝试使用相同的语句substr()。内存使用量的差异非常小。几乎没有。

那是为了你的贡献,我仍在试图找出为什么会发生这种情况。

4

6 回答 6

5

使用 substr 来避免内存不足preg_replace(),如下所示:

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

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

这在 PHP 文档中也有明确警告,请参阅一些示例:

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

于 2013-04-17T12:26:43.367 回答
3

不要使用字符串函数来替换大字符串中的某些内容。您可以循环浏览文件的行,然后在找到所需内容后中断。在此处查看 PHP 文档:

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

基本上是@cbuckley 刚才所说的:p

于 2013-04-17T12:25:11.800 回答
1

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

$lines = file($path);
array_shift($lines);
$data = implode("\n", $lines);
于 2013-04-17T12:26:09.360 回答
1

而不是使用file_get_contents()它一次获取整个文件,这可能太大而无法运行正则表达式,您应该与(http://php.net/fgetsfopen() )结合使用。此函数逐行获取文件。fgets()

然后,您可以选择在特定行上执行正则表达式。或者在您的情况下,只需跳过整行。

所以代替:

$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.
    }
}
于 2013-04-21T07:49:05.013 回答
0

我建议您在包含缓存文件的文件中使用它:

define('INCLUDESALLOW', 1);

并在将包含的文件中:

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

然后只需使用include而不是file_get_contents. 这将运行包含的 PHP 代码,但不能 100% 确定这是否是您需要的。

于 2013-04-17T12:25:59.133 回答
0

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

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

memory_limit = 32M

或者您可以像这样在脚本中覆盖它:

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

有关 PHP 内存限制的更多信息,您可以查看This SO questionini.memory-limit

于 2013-04-19T17:47:47.823 回答