web-dev-qa-db-ja.com

変数のメモリフットプリント(サイズ)を決定する方法は?

PHP(またはPHP拡張))に、特定の変数が使用するメモリ量を調べる関数がありますか?sizeof要素/プロパティの数。

memory_get_usageは、wholeスクリプトで使用されるメモリサイズを提供するのに役立ちます。単一の変数に対してこれを行う方法はありますか?

これは開発マシン上にあるため、拡張機能またはデバッグツールのロードは実行可能です。

99
Piskvor

おそらくメモリプロファイラーが必要です。 SOから情報を収集しましたが、あなたにも役立つかもしれない重要なものをコピーしました。

おそらくご存知のとおり、Xdebugはバージョン2. *以降、メモリプロファイリングのサポートを廃止しました。ここで「削除された関数」の文字列を検索してください: http://www.xdebug.org/updates.php

削除された関数

メモリプロファイリングのサポートが削除されました。これは適切に機能しなかったためです。

その他のプロファイラーオプション

php-memory-profiler

https://github.com/arnaud-lb/php-memory-profiler 。これは、Ubuntuサーバーでこれを有効にするために行ったことです。

Sudo apt-get install libjudy-dev libjudydebian1
Sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
Sudo php5enmod memprof
service Apache2 restart

そして、私のコードで:

<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

最後に、callgrind.outKCachegrind のファイル

Google gperftoolsの使用(推奨!)

まず最初にGoogle gperftoolsをインストールします。最新のパッケージをダウンロードします: https://code.google.com/p/gperftools/

それからいつものように:

Sudo apt-get update
Sudo apt-get install libunwind-dev -y
./configure
make
make install

あなたのコードで:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

次に、ターミナルを開いて起動します。

pprof --web /tmp/profile.heap

pprofは、以下に示すようなものを使用して、既存のブラウザセッションに新しいウィンドウを作成します。

PHP memory profiling with memprof and gperftools

Xhprof + Xhgui(CPUとメモリの両方をプロファイルするのに私の意見では最高です)

XhprofおよびXhguiを使用すると、CPUの使用状況をプロファイルできます現時点で問題になっている場合のメモリ使用量。非常に完全なソリューションであり、完全に制御でき、ログはmongoまたはファイルシステムの両方に書き込むことができます。

詳細については こちらを参照

ブラックファイア

Blackfireは、PHP SymsonyLabs、Symfony2のプロファイラーです https://blackfire.io/

puphpet を使用して仮想マシンをセットアップすると、サポートされていることがわかります;-)

Xdebugとトレースメモリ使用量

XDEBUG2 はPHPの拡張機能です。 Xdebugでは、パラメーターと戻り値を含むすべての関数呼び出しをさまざまな形式でファイルに記録できます。3つの出力形式があります。 1つは人間が読める形式のトレースを意味し、もう1つは解析しやすいという点でコンピュータープログラムにより適しています。この設定により、2つの異なる形式を切り替えることができます。例は こちらから入手可能

勢い

forp シンプル、非侵入型、プロダクション指向、PHPプロファイラー。

  • 各機能の時間と割り当てられたメモリの測定

  • CPU使用率

  • 関数呼び出しのファイルと行番号

  • googleのトレースイベント形式として出力

  • 機能の説明

  • 機能のグループ化

  • 関数のエイリアス(匿名関数に便利)

DBG

[〜#〜] dbg [〜#〜] はフル機能のphpデバッガーであり、phpスクリプトのデバッグに役立つインタラクティブなツールです。本番および/または開発用のWEBサーバーで動作し、IDEまたはコンソールおよびその機能からスクリプトをローカルまたはリモートでデバッグできます。

  • リモートおよびローカルデバッグ

  • 明示的および暗黙的なアクティベーション

  • 関数呼び出し、動的および静的メソッド呼び出し、パラメーターを含む呼び出しスタック

  • 対応する(ネストされた)場所の変数を評価する機能を備えた呼び出しスタックのナビゲーション

  • ステップイン/ステップアウト/ステップオーバー/カーソルの実行機能

  • 条件付きブレークポイント

  • グローバルブレークポイント

  • エラーと警告のログ

  • 並列デバッグ用の複数の同時セッション

  • GUIおよびCLIフロントエンドのサポート

  • サポートされているIPv6およびIPv4ネットワーク

  • デバッガーによって転送されるすべてのデータは、オプションでSSLで保護できます

42
Vineet1982

単一の変数のメモリ使用量を取得する直接的な方法はありませんが、ゴードンが示唆したように、memory_get_usage。これにより、割り当てられたメモリの合計量が返されるため、回避策を使用して前後の使用量を測定し、単一の変数の使用量を取得できます。これは少しハッキーですが、動作するはずです。

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

これは決して信頼できる方法ではないことに注意してください。変数の割り当て中にメモリに触れるものが他にないことは確信できないため、これは近似値としてのみ使用してください。

関数内で変数のコピーを作成し、使用されているメモリを測定することにより、実際に関数に変換できます。これをテストしていませんが、原則として、私はそれで何の問題も見ません:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $tmp = unserialize(serialize($var));
    return memory_get_usage() - $start_memory;
}
92
Tatu Ulmanen

いいえ、ありません。ただし、 serialize($var) を使用して、結果の strlen で近似を確認できます。

23
Aistina

Tatu Ulmanensの回答への回答:

注意すべきこと $start_memory自体がメモリを占有します(PHP_INT_SIZE * 8)。

したがって、関数全体は次のようになります。

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $var = unserialize(serialize($var));
    return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}

これを追加の回答として追加して申し訳ありませんが、回答にまだコメントできません。

更新:* 8は明確ではありません。明らかにphpのバージョンに依存し、おそらく64/32ビットに依存します。

20
para

見る:

ただし、これは特定の変数のメモリ使用量を提供しないことに注意してください。ただし、変数を割り当てる前後にこれらの関数を呼び出して、値を比較できます。これにより、使用されているメモリの概要がわかります。

PECL extension Memtrack も見ることができますが、ドキュメントは、言うまでもなく、事実上存在しません。

4
Gordon

コールバックの戻り値でメモリの差を計算することを選択できます。 PHP 5.3+。

function calculateFootprint($callback) {
    $startMemory = memory_get_usage();
    $result = call_user_func($callback);
    return memory_get_usage() - $startMemory;
}

$memoryFootprint = calculateFootprint(
    function() {
        return range(1, 1000000);
    }
);

echo ($memoryFootprint / (1024 * 1024)) . ' MB' . PHP_EOL;
3
Liviu Bundă

2つの変数がメモリ内の同じ割り当てられたスペースを共有できるため、変数の正確なフットプリントを遡及的に計算することはできません

2つの配列間でメモリを共有してみましょう。2番目の配列を割り当てると、最初の配列の半分のメモリが必要になることがわかります。最初のメモリの設定を解除すると、ほとんどすべてのメモリが2番目のメモリで使用されます。

_echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)
_

したがって、最初の配列の設定を解除するとfalseになるため、2番目の配列がメモリの半分を使用していると結論付けることはできません。

PHPでメモリがどのように割り当てられ、どのように使用されるかについての完全なビューについては、次の記事を読むことをお勧めします。 PHP配列は値)本当に? (ヒント:BIG!)

PHPドキュメントの Reference Counting Basics には、メモリの使用に関する多くの情報もあり、共有データセグメントへの参照カウントも含まれています。

ここで公開されているさまざまなソリューションは近似に適していますが、PHPメモリの微妙な管理を処理できるものはありません。

  1. 新しく割り当てられたスペースの計算

割り当て後に新しく割り当てられたスペースが必要な場合は、割り当ての前後にmemory_get_usage()を使用する必要があります。コピーで使用すると、現実の誤った見方が得られます。

_// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();

echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";
_

最初のmemory_get_usage()の結果を保存する場合、変数は前に既に存在している必要があり、memory_get_usage()は別の時間に呼び出され、他のすべての関数も呼び出される必要があることに注意してください。

上記の例のようにエコーしたい場合は、出力バッファーを開くために必要なアカウンティングメモリを回避するために、出力バッファーを既に開いている必要があります。

  1. 必要なスペースの計算

関数を使用して変数のコピーを保存するために必要なスペースを計算する場合、次のコードがさまざまな最適化を処理します。

_<?php
function getMemorySize($value) {
    // existing variable with integer value so that the next line
    // does not add memory consumption when initiating $start variable
    $start=1;
    $start=memory_get_usage();
    // json functions return less bytes consumptions than serialize
    $tmp=json_decode(json_encode($value));
    return memory_get_usage() - $start;
}

// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);

// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
    // call the function name once 
    range(1,1);

    // we will compare the two values (see comment above about initialization of $start)
    $start=1;
    $start=memory_get_usage();
    $c=range(1,100);
    echo memory_get_usage()-$start."\n";
    echo getMemorySize($c)."\n";
}
test();

// same result, this works fine.
// 11044
// 11044
_

変数名のサイズは、割り当てられたメモリ内で重要であることに注意してください。

  1. コードを確認してください!!

変数の基本サイズは、PHPソースコードで使用される内部C構造によって定義されます。このサイズは、数値の場合に変動しません。文字列の場合、文字列の長さが追加されます。

_typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;
_

変数名の初期化を考慮しない場合、変数がどれだけ使用するかは既にわかっています(数字と文字列の場合):

数字の場合は44バイト

+文字列の場合は24バイト

+文字列の長さ(最後のNUL文字を含む)

(これらの数字はPHPバージョンによって変わる可能性があります)

メモリのアライメントのため、4バイトの倍数に切り上げる必要があります。変数が(関数内ではなく)グローバル空間にある場合、さらに64バイトを割り当てます。

したがって、このページ内のコードのいずれかを使用する場合は、いくつかの簡単なテストケース(文字列または数字)を使用した結果が、この投稿のすべての指示($ _GLOBAL配列、最初の関数呼び出し、出力バッファ、...)

3
Adam

私は同様の問題を抱えていたので、使用した解決策は変数をファイルに書き込み、そのファイルに対してfilesize()を実行することでした。大体このようになります(テストされていないコード):

function getVariableSize ( $foo ) 
{
    $tmpfile = "temp-" . microtime(true) . ".txt";
    file_put_contents($tmpfile, $foo);
    $size = filesize($tmpfile);
    unlink($tmpfile);
    return $size;
}

このソリューションはディスクIOを使用するため、それほど高速ではありませんが、memory_get_usageトリックよりもはるかに正確なものを提供するはずです。必要な精度に依存します。

2
Alan Bellows
function mesure($var){
    $start = memory_get_usage();
    if(is_string($var)){
        $newValue = $var . '';
    }elseif(is_numeric($var)){
        $newValue = $var + 0;
    }elseif(is_object($var)){
        $newValue = clone $var;
    }elseif(is_array($var)){
        $newValue = array_flip($var, []);
    }
    return memory_get_usage() - $start;
}
1
Abdelilah

試したことはありませんが、Xdebugトレースでは xdebug.collect_assignment sで十分です。

1
Arkh

次のスクリプトは、1つの変数の合計メモリ使用量を示しています。

function getVariableUsage($var) {
  $total_memory = memory_get_usage();
  $tmp = unserialize(serialize($var));
  return memory_get_usage() - $total_memory; 
}

$var = "Hey, what's you doing?";
echo getVariableUsage($var);

これをチェックしてください

http://www.phpzag.com/how-much-memory-do-php-variables-use/

0