memory_get_peak_usage(),带有"真实用途"

the*_*cat 84 php memory memory-management

如果real_usage参数设置为truePHP DOCS,则说它将获得从系统分配的实际内存大小.如果它是false它将获得报告的内存emalloc()

这两个选项中的哪一个返回最大值.相对于php.ini中的内存限制值分配的内存?

我想知道脚本达到这个限制有多接近.

Nik*_*ams 127

好吧,让我们使用一个简单的脚本来测试它:

ini_set('memory_limit', '1M');
$x = '';
while(true) {
  echo "not real: ".(memory_get_peak_usage(false)/1024/1024)." MiB\n";
  echo "real: ".(memory_get_peak_usage(true)/1024/1024)." MiB\n\n";
  $x .= str_repeat(' ', 1024*25); //store 25kb more to string
}
Run Code Online (Sandbox Code Playgroud)

输出:

not real: 0.73469543457031 MiB
real: 0.75 MiB

not real: 0.75910949707031 MiB
real: 1 MiB

...

not real: 0.95442199707031 MiB
real: 1 MiB

not real: 0.97883605957031 MiB
real: 1 MiB

PHP Fatal error:  Allowed memory size of 1048576 bytes exhausted (tried to allocate 793601 bytes) in /home/niko/test.php on line 7
Run Code Online (Sandbox Code Playgroud)

似乎真正的用法是从系统分配的内存 - 它似乎分配在比脚本当前需要的更大的桶中.(我猜是出于性能原因).这也是php进程使用的内存.

$real_usage = false用法是,你实际上是在你的脚本中使用的内存使用情况,而不是由Zend的内存管理器分配的内存的实际金额.

阅读此问题以获取更多信息.

简而言之:要获得与内存限制的距离,请使用 $real_usage = true

  • Zend引擎以256K块的形式分配内存."实际使用"值是所有这些块的总和.这实际上是用于触发内存耗尽错误的值:`if(segment_size <true_size || heap-> real_size + segment_size> heap-> limit){/*内存限制溢出*/`. (5认同)
  • 正如@cleong解释的那样,这个答案实际上是错误的,尽管有所有的赞成.`memory_get_usage(true)`返回应该与`memory_limit`进行比较的值.答案中给出的例子太简单了,因为没有"浪费"的记忆".会发生的是"真正的"分配的内存需要从"1 MiB"增加到"1.25 MiB",这就是触发致命错误的原因我有一个复杂的批处理脚本,其内存限制为120 MiB,当它被中止时,由于"实际"分配的内存达到了限制,因此只有"80 MiB"的"非实际"分配内存. (4认同)
  • “不真实”的值是调用emalloc请求所请求的字节数的总和(加上用于标头和内存对齐的字节数)。它不反映由于块无法放入已分配的段中剩余的空间而浪费的内存。如果更改示例以分配(1024 * 256)字节和2M限制,则两者之间的差异将变得更加明显。 (2认同)

Bab*_*aba 33

介绍

你应该使用,memory_get_usage(false)因为你想要的是内存使用而不是内存分配.

有什么不同

Google Mail可能已经25MB为您分配了存储空间,但这并不意味着您现在使用的是存储空间.

这正是PHP文档所说的

将其设置为TRUE以获取从系统分配的实际内存大小.如果未设置或FALSE,则仅报告emalloc()使用的内存.

两个参数都将返回相对于内存限制分配的内存,但主要区别在于:

memory_get_usage(false)给所使用的内存emalloc(),而memory_get_usage(true)返回里程碑,可以在这里示范记忆里店

我想知道脚本达到这个限制有多接近.

这需要一些数学,可能只适用于循环或特定用例.我为什么这么说?

想像

ini_set('memory_limit', '1M');
$data = str_repeat(' ', 1024 * 1024);
Run Code Online (Sandbox Code Playgroud)

The above script would fail before you even get the chance to start start checking memory.

据我所知,我可以检查用于PHP的变量或特定部分的内存的唯一方法是:

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;
Run Code Online (Sandbox Code Playgroud)

请参阅说明,但如果您处于循环或递归函数中,则可以使用最大内存使用量来在达到内存查看时安全地进行估计.

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

$memoryAvailable = filter_var(ini_get("memory_limit"), FILTER_SANITIZE_NUMBER_INT);
$memoryAvailable = $memoryAvailable * 1024 * 1024;

$peekPoint = 90; // 90%

$memoryStart = memory_get_peak_usage(false);
$memoryDiff = 0;

// Some stats
$stat = array(
        "HIGHEST_MEMORY" => 0,
        "HIGHEST_DIFF" => 0,
        "PERCENTAGE_BREAK" => 0,
        "AVERAGE" => array(),
        "LOOPS" => 0
);

$data = "";
$i = 0;
while ( true ) {
    $i ++;

    // Get used memory
    $memoryUsed = memory_get_peak_usage(false);

    // Get Diffrence
    $memoryDiff = $memoryUsed - $memoryStart;

    // Start memory Usage again
    $memoryStart = memory_get_peak_usage(false);

    // Gather some stats
    $stat['HIGHEST_MEMORY'] = $memoryUsed > $stat['HIGHEST_MEMORY'] ? $memoryUsed : $stat['HIGHEST_MEMORY'];
    $stat['HIGHEST_DIFF'] = $memoryDiff > $stat['HIGHEST_DIFF'] ? $memoryDiff : $stat['HIGHEST_DIFF'];
    $stat['AVERAGE'][] = $memoryDiff;
    $stat['LOOPS'] ++;
    $percentage = (($memoryUsed + $stat['HIGHEST_DIFF']) / $memoryAvailable) * 100;

    // var_dump($percentage, $memoryDiff);

    // Stop your scipt
    if ($percentage > $peekPoint) {

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;
    }

    $data .= str_repeat(' ', 1024 * 25); // 1kb every time
}
Run Code Online (Sandbox Code Playgroud)

产量

Stoped at: 95.86%
{
    "HIGHEST_MEMORY": "0.71",
    "HIGHEST_DIFF": "0.24",
    "PERCENTAGE_BREAK": "95.86%",
    "AVERAGE": "0.04",
    "LOOPS": 11
}
Run Code Online (Sandbox Code Playgroud)

现场演示

这可能仍然失败

它可能会失败,因为在if ($percentage > $peekPoint) { 此之后仍然添加执行额外任务也会消耗内存

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;
Run Code Online (Sandbox Code Playgroud)

If the memory to process this request is grater than the memory available the script would fail.

结论

它不是一个完美的解决方案,但会间隔检查内存,如果它立即超过偷看(例如90%) exit并留下花哨的东西


Gli*_*ire 7

real_usagefalse报告脚本使用的用法.这将是两者中更准确的.

real_usagetrue报告分配给脚本的内存.这将是两者中的较高者.

我可能会使用,true如果我试图比较,因为你的脚本永远不会分配超过内存限制,并且只要它(加上所有其他脚本)没有超过该用法,它将继续运行.

  • 不,正如我的脚本所示,real_usage true更高 (4认同)
  • 恰恰相反:“false”是脚本*使用*的内存,“true”是*分配*的内存。 (2认同)