PHP(またはPHP拡張)には、特定の変数が使用するメモリの量を調べる関数はありますか?sizeof
要素/プロパティの数を教えてくれます。
memory_get_usage
スクリプト全体で使用されるメモリサイズを取得するのに役立ちます。単一の変数に対してこれを行う方法はありますか?
これは開発マシン上にあるため、拡張機能やデバッグツールの読み込みが可能であることに注意してください。
PHP(またはPHP拡張)には、特定の変数が使用するメモリの量を調べる関数はありますか?sizeof
要素/プロパティの数を教えてくれます。
memory_get_usage
スクリプト全体で使用されるメモリサイズを取得するのに役立ちます。単一の変数に対してこれを行う方法はありますか?
これは開発マシン上にあるため、拡張機能やデバッグツールの読み込みが可能であることに注意してください。
回答:
おそらくメモリプロファイラが必要です。私はSOから情報を集めましたが、あなたにも役立つかもしれないいくつかの重要なことをコピーしました。
おそらくご存じのとおり、Xdebugは2. *バージョン以降、メモリプロファイリングのサポートを終了しました。ここで「削除された関数」の文字列を検索してください:http : //www.xdebug.org/updates.php
削除された機能
正しく動作しなかったため、メモリプロファイリングのサポートを削除しました。
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"));
最後にKCachegrindでcallgrind.out
ファイルを開きます
まず最初に、https://code.google.com/p/gperftools/から最新のパッケージをダウンロードして、Google 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は、既存のブラウザーセッションで、以下に示すような新しいウィンドウを作成します。
XhprofとXhguiそれは現時点ではあなたの問題だ場合は、同様または単にメモリ使用量、CPU使用率をプロファイリングすることができます。これは非常に完全なソリューションであり、完全に制御でき、ログはmongoまたはファイルシステムの両方に書き込むことができます。
Blackfireは、Symfony2の仲間であるSensioLabsによるPHPプロファイラーです。https: //blackfire.io/
puphpetを使用して仮想マシンをセットアップする場合は、サポートされていることを確認できます;-)
XDEBUG2はPHPの拡張機能です。Xdebugを使用すると、パラメーターや戻り値を含むすべての関数呼び出しをさまざまな形式でファイルに記録できます。3つの出力形式があります。1つは人間が読み取れるトレースを意味し、もう1つは解析が容易なためコンピュータープログラムにより適しています。最後の1つはHTMLを使用してトレースをフォーマットします。設定で2つの異なるフォーマットを切り替えることができます。例はここあります
forpシンプル、非侵入型、プロダクション指向のPHPプロファイラー。一部の機能は次のとおりです。
各機能の時間と割り当てられたメモリの測定
CPU使用率
関数呼び出しのファイルと行番号
Googleのトレースイベント形式として出力
関数のキャプション
関数のグループ化
関数のエイリアス(無名関数に役立ちます)
DBGは、フル機能のPHPデバッガーです。これは、PHPスクリプトのデバッグに役立つインタラクティブなツールです。本番および/または開発用のWEBサーバーで動作し、IDEまたはコンソールからローカルまたはリモートでスクリプトをデバッグできます。その機能は次のとおりです。
リモートおよびローカルのデバッグ
明示的および暗黙的なアクティブ化
関数呼び出し、動的および静的メソッド呼び出しを含む呼び出しスタックとそのパラメーター
対応する(ネストされた)場所で変数を評価する機能を備えたコールスタックを介したナビゲーション
ステップイン/ステップアウト/ステップオーバー/カーソル機能まで実行
条件付きブレークポイント
グローバルブレークポイント
エラーと警告のロギング
並列デバッグのための複数の同時セッション
GUIおよびCLIフロントエンドのサポート
サポートされているIPv6およびIPv4ネットワーク
デバッガーによって転送されたすべてのデータは、オプションでSSLで保護できます
単一の変数のメモリ使用量を直接取得する方法はありませんが、Gordonが示唆したように、を使用できますmemory_get_usage
。これにより、割り当てられたメモリの合計量が返されるため、回避策を使用して、1つの変数の使用量を取得する前と後に使用量を測定できます。これは少しハッキーですが、動作するはずです。
$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;
}
$tmp = $var
浅いコピーを作成します。$ tmpが変更されるまで、これはより多くのメモリを割り当てません。
$tmp = unserialize(serialize($var))
ですか; これは、上記のAistinaのアプローチを組み合わせたものです。
$var
は関数に渡されたものの浅いコピーまたは参照であるため、は必要ありませんが$tmp
、に再割り当てでき$var
ます。これにより、内部参照がから$tmp
に保存され$var
ます。
$tmp
からは$var
?
いいえ、ありません。ただし、結果のを概算してserialize($var)
確認できますstrlen
。
strlen(serialize(array(1,2,3)))
30である
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ビットに依存している可能性があります。
* 8
?ありがとう!
PHP_INT_SIZE
バイト、しかしPHP_INT_SIZE*8
。あなたはこの関数を呼び出すことによって、それが0を返す必要があることを試すことができます:function sizeofvar() { $start_memory = memory_get_usage(); return memory_get_usage() - $start_memory - PHP_INT_SIZE*8; }
8
一定していないようです。私の開発システム(PHP 5.6.19)でのコメント関数に従って、を返します-16
。また、興味深いことに、からphp -a
、関数の2行を呼び出すと、さまざまな異なる値が得られます。
見る:
memory_get_usage()
— PHPに割り当てられたメモリの量を返しますmemory_get_peak_usage()
— PHPによって割り当てられたメモリのピークを返しますただし、これは特定の変数のメモリ使用量を提供しないことに注意してください。ただし、変数を割り当てる前後にこれらの関数を呼び出して、値を比較することができます。これにより、使用されているメモリがわかります。
PECL拡張機能Memtrackを確認することもできますが、ドキュメントには事実上、存在しないというか、少し不足しています。
コールバックの戻り値でメモリの違いを計算することを選択できます。これは、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;
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でメモリがどのように割り当てられ、どのように使用されるかについては、次の記事を読むことをお勧めします。(ヒント:BIG!)
PHPドキュメントの「参照カウントの基本」にも、メモリの使用に関する多くの情報があり、参照は共有データセグメントにカウントされます。
ここで公開されているさまざまなソリューションは近似に適していますが、PHPメモリの微妙な管理を処理できるものはありません。
割り当て後に新しく割り当てられたスペースが必要な場合は、割り当ての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()
もう一度呼び出される必要があり、他のすべての関数も呼び出される必要があります。
上記の例のようにエコーする場合は、出力バッファーを開くために必要なアカウンティングメモリを回避するために、出力バッファーを既に開いている必要があります。
変数のコピーを保存するために必要なスペースを計算するために関数に依存したい場合は、次のコードがさまざまな最適化を処理します。
<?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
割り当てられるメモリでは、変数名のサイズが重要であることに注意してください。
変数の基本サイズは、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バイトを割り当てます。
したがって、このページ内のコードの1つを使用する場合は、いくつかの簡単なテストケース(文字列または数値)を使用した結果が、この投稿($ _GLOBAL配列、最初の関数呼び出し、出力バッファ、...)
zvalue
、is_ref
およびコピーオンライトに入る前でさえあります。ありがとうございました。
私にも同様の問題があり、私が使用した解決策は、変数をファイルに書き込んでから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のトリックよりもはるかに正確なものを提供するはずです。必要な精度に依存します。
strlen
はより簡単になることに注意してください。
試したことはありませんが、xdebug.collect_assignmentを使用したXdebugトレースで十分な場合があります。
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つの変数の合計メモリ使用量を示しています。
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);
これをチェック