Php 内存“获取”峰值使用率()和;“实际使用”;

Php 内存“获取”峰值使用率()和;“实际使用”;,php,memory,memory-management,Php,Memory,Memory Management,如果real\u usage参数设置为true,PHP文档会说它将获得从系统分配的实际内存大小。如果它是false它将获得emalloc()报告的内存 这两个选项中的哪一个返回相对于php.ini中的内存限制值分配的最大内存 我想知道脚本达到该极限的距离有多近。real\u usagefalse报告脚本使用的情况。这将是两种方法中比较准确的一种 real\u usagetrue报告分配给脚本的内存。这将是两者中较高的一个 如果我试图进行比较,我可能会使用true,因为您的脚本分配的内存永远不会超

如果
real\u usage
参数设置为
true
,PHP文档会说它将获得从系统分配的实际内存大小。如果它是
false
它将获得
emalloc()报告的内存

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


我想知道脚本达到该极限的距离有多近。

real\u usage
false报告脚本使用的情况。这将是两种方法中比较准确的一种

real\u usage
true报告分配给脚本的内存。这将是两者中较高的一个


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

好的,让我们用一个简单的脚本来测试这个问题:

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
}
输出:

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
看起来真正的使用是从系统中分配的内存——它似乎分配在比脚本当前需要的更大的存储桶中。(我想是出于性能原因)。这也是php进程使用的内存

$real\u usage=false
使用率是您在脚本中实际使用的内存使用率,而不是Zend内存管理器分配的实际内存量

阅读了解更多信息


简而言之:要了解您离内存限制有多近,请使用
$real\u usage=true

简介

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
}
您应该使用
memory\u get\u usage(false)
,因为您需要的是已使用的内存,而不是已分配的内存

有什么区别

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
}
您的
googlemail
可能已经为您分配了
25MB
的存储空间,但这并不意味着您目前使用的就是这些存储空间

这正是PHP文档所说的

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

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

memory\u get\u usage(false)
给出
emalloc()
使用的内存,而
memory\u get\u usage(true)
返回可以在此处演示的里程碑

我想知道脚本有多接近这个极限。

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

想象

在您有机会开始检查内存之前,上述脚本就会失败

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

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;
,但如果您处于循环或递归函数中,则可以使用最大内存使用量来安全地估计何时达到内存峰值

示例

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
}

这仍然可能失败

它可能会失败,因为在
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;
如果处理此请求的内存大于可用内存,脚本将失败。

结论

这不是一个完美的解决方案,但要每隔一段时间检查内存,如果内存超过峰值(例如90%)
立即退出
,并按照PHP的要求保留那些花哨的东西

实际使用

将此设置为TRUE,以获取从系统分配的总内存,包括未使用的页面。如果未设置或为FALSE,则仅报告已使用的内存

因此,要获取脚本使用的内存,应该使用memory\u get\u usage(),因为默认的真实使用率为false

如果您想获得系统分配的内存,但不关心实际使用了多少,请使用memory\u get\u usage(true);



我想让大家看看Julien Pauli在2013年php英国会议上的一篇演讲,他在演讲中谈到了php内部的内存工作原理。还可以看到Zend引擎将内存分配为256K块。“实际使用”值是所有这些块的总和。这实际上是用于触发内存耗尽错误的值:
如果(segment_sizereal_size+segment_size>heap->limit){/*内存限制溢出*/
。“not real”值是调用
emalloc
请求的字节数之和(加上用于头和内存对齐的字节数)。这并不反映由于块不适合已分配段中剩余的空间而造成的内存浪费。如果您将示例更改为分配(1024*256)字节和2M限制,两者之间的差异将变得更加明显。@Niko,您为什么使用内存使用率而不是内存使用率?我们不应该禁用()使用memory\u get\u usage来获得更准确的结果?@Pacerier问题是如何接近脚本的极限-因为这个峰值是有意义的,正如@cleong所解释的,这个答案实际上是错误的,尽管有所有的投票。
memory\u get\u usage(true)
返回应与
内存限制进行比较的值。
答案中给出的示例太简单,因为没有“浪费”内存。实际分配的内存需要从“1 MiB”增加到“1.25 MiB”这就是触发致命错误的原因。我有一个内存限制为120 MiB的复杂批处理脚本,当它被中止时,“非真实”分配的内存只有“80 MiB”,因为“真实”分配的内存达到了极限。正好相反:
false
是脚本使用的内存,
true
是分配的内存。@Benjamin是的,不知道为什么我会这么盲目地错。嗯,修复了。
memory\u limit
选项是关于堆还是堆栈的?如果我有两个脚本并行或多个请求,怎么办函数的作用是:返回用于所有t
<!-- Print CPU memory and load -->
<?php
$output = shell_exec('free');
$data = substr($output,111,19);
echo $data;
echo file_get_contents('/proc/loadavg');
$load = sys_getloadavg();
$res = implode("",$load);
echo $res;
?>