具有“实际用法”的memory_get_peak_usage()


91

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

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

我想知道脚本达到该极限有多接近。


8
我想向您指出Julien Pauli 在2013年php uk大会上的演讲youtube.com/watch?v=sm1HUrnsxLI,他在会上谈到了内存在PHP内部的工作方式。
mpratt

Answers:


136

好的,让我们使用一个简单的脚本对此进行测试:

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的内存管理器分配的内存的实际金额。

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

简而言之:要使您接近内存限制,请使用 $real_usage = true


5
Zend引擎以256K块分配内存。“实际使用量”值是所有这些块的总和。这实际上是用于触发内存耗尽错误的值:if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */
cleong

2
“不真实”值是调用所请求的字节数的总和emalloc(加上用于标头和内存对齐的字节数)。它不反映由于块无法放入已分配的段中剩余的空间而浪费的内存。如果更改示例以分配(1024 * 256)字节和2M限制,则两者之间的差异将变得更加明显。
cleong

@Niko,您为什么使用memory_get_peak_usage而不是memory_get_usage?我们不应该gc_disable()并使用memory_get_usage获得更准确的结果吗?
Pacerier

@Pacerier的问题是要接近脚本的限制-对于这个高峰,我会说
Niko Sams

4
正如@cleong所解释的,尽管有所有支持,但这个答案实际上是错误的。memory_get_usage(true)应该与进行比较的返回值memory_limit。答案中给出的示例太简单了,因为没有“浪费的”内存。发生的情况是,“实际”分配的内存需要从“ 1 MiB”增加到“ 1.25 MiB”,这才引发致命错误我有一个复杂的批处理脚本,其内存限制为120 MiB,由于“实际”分配的内存已达到限制,中止时“非真实”分配的内存仅为“ 80 MiB”
Martin Prikryl 2014年

36

介绍

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

有什么不同

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

这正是PHP文档所说的

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

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

memory_get_usage(false)给出emalloc()while 所使用的内存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;

请参阅说明,但是如果您处于循环或递归函数中,则可以使用最大内存使用量来安全地估计何时达到内存窥视。

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
}

输出量

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

现场演示

这可能仍然失败

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

结论

这不是一个完美的解决方案,但要定期检查内存,并exit立即检查内存是否超过(例如90%) 并留下奇特的东西


memory_limit关于堆的选择吗?还是堆栈?
Yousha Aleayoub '18

如果我有两个并行或多个请求的脚本,则memory_get_usage()函数返回用于同时执行所有这些脚本或仅实际脚本的内存?
Mohammed Yassine CHABLI

7

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

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

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


1
恰恰相反:false是脚本使用true的内存,是分配的内存。
本杰明·

1
@Benjamin是的,不确定我为什么这么盲目地弄错了。嗯,固定。
Glitch Desire

2

根据PHP memory_get_usage

实际使用

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

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

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


-1
<!-- 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;
?>

1
欢迎来到Stackoverflow!你能告诉我们答案是什么吗?不仅是代码,还包括您如何解决该问题。谢谢!
Gilles Heinesch '19

尽管您的答案可能会提供一些可能有用的信息,但它与所提出的问题无关。您可能要解释您的答案与所问问题的关系。
Moritur
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.