【问题标题】:memory_get_peak_usage() with "real usage"memory_get_peak_usage() 与“实际使用情况”
【发布时间】:2013-03-22 15:24:31
【问题描述】:

如果real_usage 参数设置为true,PHP DOCS 说它将获得系统分配的实际内存大小。如果是false会得到emalloc()报告的内存

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

我想知道脚本有多接近该限制。

【问题讨论】:

标签: php memory memory-management


【解决方案1】:

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

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_usage = false 使用量是您在脚本中实际使用的内存使用量,而不是 Zend 内存管理器分配的实际内存量。

阅读this question了解更多信息。

简而言之:要了解您与内存限制的距离有多近,请使用$real_usage = true

【讨论】:

  • Zend 引擎以 256K 块分配内存。 “实际使用”值是所有这些块的总和。这实际上是用于触发内存耗尽错误的值:if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */
  • “非真实”值是调用emalloc 请求的字节数的总和(加上标头和内存对齐的字节数)。它不反映由于块不适合已分配段中剩余的空间而浪费的内存。如果您将示例更改为分配 (1024 * 256) 字节和 2M 限制,则两者的差异将变得更加明显。
  • @Niko,你为什么使用 memory_get_peak_usage 而不是 memory_get_usage ?我们不应该 gc_disable() 并使用 memory_get_usage 来获得更准确的结果吗?
  • @Pacerier 的问题是要让脚本接近极限 - 因为那个峰值是有道理的,我会说
  • 正如@cleong 解释的那样,这个答案实际上是错误的,尽管大家都赞成。 memory_get_usage(true) 返回的值应与 memory_limit 进行比较。答案中给出的示例太简单了,因为没有“浪费的”内存”。发生的情况是“实际”分配的内存需要从“1 MiB”增加到“1.25 MiB”,这就是触发致命错误的原因. 我有一个复杂的批处理脚本,内存限制为 120 MiB,当它被中止时,“非真实”分配的内存只有“80 MiB”,因为“真实”分配的内存达到了限制。
【解决方案2】:

简介

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

有什么区别

您的Google Mail 可能已经为您分配了25MB 的存储空间,但这并不意味着您目前使用的就是这些。

这正是 PHP 文档所说的

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

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

memory_get_usage(false) 给出emalloc() 使用的内存,而memory_get_usage(true) 返回里程碑,可以在这里演示Memory Mile Store

我想知道脚本有多接近该限制。

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

想象一下

ini_set('memory_limit', '1M');
$data = str_repeat(' ', 1024 * 1024);

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;

See Explanation,但如果您处于循环或递归函数中,您可以使用最大内存使用量来安全地估计何时会达到内存峰值。

示例

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
}

Output

Stoped at: 95.86%
{
    "HIGHEST_MEMORY": "0.71",
    "HIGHEST_DIFF": "0.24",
    "PERCENTAGE_BREAK": "95.86%",
    "AVERAGE": "0.04",
    "LOOPS": 11
}

Live Demo

这可能仍然失败

它可能会失败,因为在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;

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

结论

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

【讨论】:

  • memory_limit 是关于堆的选项吗?还是堆栈?
  • 如果我有两个并行的脚本或多个请求,那么 memory_get_usage() 函数会返回用于同时执行的所有脚本或仅实际脚本的内存?
【解决方案3】:

real_usage false 报告您的脚本使用的使用情况。这将是两者中更准确的一个。

real_usage true 将内存分配报告给您的脚本。这将是两者中较高的一个。

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

【讨论】:

  • 正好相反:false 是脚本使用的内存,true分配的内存。
  • @Benjamin 是的,不知道为什么我这么盲目地错了。嗯,固定。
【解决方案4】:

根据 PHP memory_get_usage

real_usage

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

所以要获取脚本使用的内存,您应该使用 memory_get_usage(),因为默认的 real_usage 为 false。

如果你想获取系统分配的内存但不关心实际使用了多少,使用memory_get_usage(true);

【讨论】:

    【解决方案5】:
    <!-- 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;
    ?>
    

    【讨论】:

    • 欢迎来到 Stackoverflow!你能告诉我们答案是什么吗?不仅是代码,还有你是如何解决这个问题的。谢谢!
    • 虽然您的回答可能会提供一些潜在有用的信息,但它与所提出的问题无关。您可能想解释您的答案与所问问题的关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    相关资源
    最近更新 更多