「実際の使用」を伴うmemory_get_peak_usage()


92

real_usage引数がtruePHP DOCSに設定されている場合は、システムから割り当てられたメモリの実際のサイズを取得します。もしそうなら、falseそれはによって報告されたメモリを取得しますemalloc()

これらの2つのオプションのどちらが最大値を返しますか。php.iniのメモリ制限値に関連して割り当てられたメモリ?

スクリプトがその制限にどれだけ近づいたかを知りたいです。


8
Julien Pauliによるphp.ukカンファレンス2013のyoutube.com/watch?v=sm1HUrnsxLIによるプレゼンテーションで、PHP内でのメモリの動作について説明します。
mpratt 2013

回答:


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 */
クレオン2013年

2
「実数ではない」値は、への呼び出しで要求されたバイト数の合計ですemalloc(ヘッダーとメモリ配置のバイト数を加えたもの)。すでに割り当てられているセグメントに残っているスペースにブロックが適合しないためにメモリが浪費されていることを反映していません。(1024 * 256)バイトと2Mの制限を割り当てるように例を変更すると、2つの違いがより明確になります。
クレオン2013年

@ニコ、なぜmemory_get_usageの代わりにmemory_get_peak_usageを使用したのですか?より正確な結果を得るために、gc_disable()を使用し、memory_get_usageを使用するべきではありませんか?
パセリエ2013

@Pacerier問題は、スクリプトがどの程度限界に近づくかでした-そのピークは理にかなっていると私は言うでしょう
Niko Sams

4
@cleongが説明したように、すべての賛成投票にもかかわらず、この答えは実際には間違っています。memory_get_usage(true)と比較されるべきである戻り値memory_limit。「無駄な」メモリがないため、回答の例は非常に単純すぎます。実際に割り当てられたメモリを「1 MiB」から「1.25 MiB」に増やす必要があり、それが致命的なエラーのトリガーになります。 。メモリ制限が120 MiBの複雑なバッチスクリプトがあり、「実際の」割り当てメモリが制限に達したために中止された場合、「実際ではない」割り当てメモリは「80 MiB」しかない
Martin Prikryl

36

前書き

必要なのはmemory_get_usage(false)、割り当てられたメモリではなく使用されたメモリなのでです。

違いは何ですか

あなたのためにストレージをGoogle Mail割り当てているかもしれ25MBませんが、それはあなたが現在使用しているものであるという意味ではありません。

これはまさにPHPドキュメントが言っていたものです

システムから割り当てられたメモリの実際のサイズを取得するには、これをTRUEに設定します。設定されていないかFALSEの場合、emalloc()が使用するメモリのみが報告されます。

どちらの引数も、メモリ制限に関連して割り当てられたメモリを返しますが、主な違いは次のとおりです。

memory_get_usage(false)emalloc()while memory_get_usage(true)が使用するメモリを返すマイルストーンはここでデモンストレーションできますメモリマイルストア

スクリプトがその制限にどれだけ近づいたかを知りたいです。

それはいくつかの計算を必要とし、ループまたは特定のユースケースでのみ機能する可能性があります。なぜ私はそんなことを言ったのですか?

想像してみて

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

2つのスクリプトを並行して実行するか、多数のリクエストを実行する場合、memory_get_usage()関数は、同時に実行されるすべてのスクリプトまたは実際のスクリプトのみに使用されるメモリを返しますか?
Mohammed Yassine CHABLI

7

real_usagefalseは、スクリプトが使用した使用法を報告します。これは2つのうちより正確になります。

real_usagetrueは、スクリプトに割り当てられたメモリを報告します。これは2つのうち高い方になります。

trueスクリプトをメモリ制限を超えて割り当てることはなく、スクリプト(および他のすべてのスクリプト)がその使用量を超えない限り実行を継続するため、比較する場合はおそらく使用します。


1
それはまったく逆です:falseメモリは、スクリプトで使用されtrueメモリで割り当てられました
ベンジャミン

1
@ベンジャミンうん、なぜ私がそんなに盲目的に間違ったのかわからない。うーん、修正。
グリッチの欲望

2

PHPのmemory_get_usageによる

real_usage

これをTRUEに設定すると、未使用のページを含め、システムから割り当てられた合計メモリが取得されます。設定されていないかFALSEの場合、使用されたメモリのみが報告されます。

したがって、スクリプトで使用されるメモリを取得するには、デフォルトのreal_usageがfalseであるため、memory_get_usage()を使用する必要があります。

システムによって割り当てられたメモリを取得したいが実際にどれだけ使用されたかを気にしない場合は、memory_get_usage(true);を使用します。


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

2
Stackoverflowへようこそ!答えは何ですか?コードだけでなく、どのようにして問題を修正するかを理解する方法も。ありがとう!
Gilles Heinesch

あなたの答えはいくつかの潜在的に有用な情報を提供するかもしれませんが、それは尋ねられている質問には関係ありません。あなたの回答が、質問されている質問とどのように関連しているかを説明したいと思うかもしれません。
Moritur
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.