PHPでオブジェクトが消費するメモリの量と64ビットバージョンを使用する価値はありますか?





この投稿は、現在の大規模なZendFrameworkプロジェクトのメモリ消費量の調査から着想を得たものです。 いつものように、研究の結果によると、私たちがプログラムの慢さにショックを受けました。これは、PHPで何か大きなものを書くときによくあります。 そして、おそらく、PHPだけではありません。



しかし、まず最初に。



この記事は、次の記事の論理的な続きです。





どのように測定しますか



まず、「重量」の測定方法を決定します。 テンプレートは次のとおりです。

$startMemory = 0; $startMemory = memory_get_usage(); //  echo (memory_get_usage() - $startMemory) . ' bytes' . PHP_EOL;
      
      





このようなテンプレートは、新しく割り当てられたメモリ、つまり変数のメモリを測定するのに適しています。 しかし、スクリプトが開始される前にメモリに保存されるため、このアプローチでどの程度の定義、つまり関数とクラスの記述が食べられるかを測定することは不可能です。 定義を測定するために、次のテンプレートを使用します。

 $startMemory = 0; $startMemory = memory_get_usage(); //  include $testfile; echo (memory_get_usage() - $startMemory - $include_overhead) . ' bytes' . PHP_EOL;
      
      





$ include_overheadは、内部のニーズに合わせてincludeステートメントが消費する量です。 この記事では、$ include_overheadの測定方法については学習しません。 消費されるメモリのサイズは、次の3つのことに依存することに注意してください。



誰もがこの詳細を調査することに興味がある場合、ファイルrun.include-test.phpを調べることができます。これは、インクルード中のメモリ消費の不均一性を非常によく示しています。 また、以下のすべてのテストでは、正確な値は必要ないが、32ビットバージョンと64ビットバージョンの傾向と違いが必要なので、およそ$ include_overheadを測定します。



「オブジェクト」の重さ



そのため、TestSuiteは、多数のテストを自動的に実行するように作成されました。 すべてのテストは、 Ubuntu 12.04.1 LTS i386およびUbuntu 12.04.1 LTS amd64の VirtualBoxで実行されました。 PHPバージョン-5.3.10、ZendFramework-1.11.11。 コンソールで実行するコマンド:

 php run.testsuite-without-accelerator.php
      
      



さらに、制御のためにGentoo amd64を使用してマシンでテストを行いました。 コンソールから起動した場合、PHPアクセラレータは機能しません。 結果は次のとおりです。

テスト名 説明 Ubuntu x86、

PHP 5.3.10、

ZF 1.11.11
Ubuntu x86-64、

PHP 5.3.10、

ZF 1.11.11
Gentoo x86-64、

PHP 5.3.15、

ZF 1.11.4
a.mention_variable 可変言及 44 80 48
a.new_null_variable 新しいヌル変数の作成 108 208 144
a.unset_null_variable 変数を削除 -108 -208 -144
stdClass.new オブジェクト作成 120 232 168
stdClass.tovar1 オブジェクトを作成して$ aをリンクする 264 512 352
stdClass.tovar2_unset_and_thesame リンク$ aを削除し、リンク$ aを再作成します 0 0 0
stdClass.tovar3_unset_and_another リンク$ aを削除してリンク$ bを作成 0 0 0
stdClass.tovar4_another オブジェクトを作成して$ cをリンクする 264 512 352
stdClass.tovar5_addlink $ aを$ bと同じオブジェクトにリンクします 64 128 96
stdClass.z.free_memory $ a、$ b、および$ cリンクの削除 -592 -1152 -800
myclass.a.empty クラスAの説明 700 1344 1128
myclass.aa.interface インターフェイスの説明A 700 1344 1128
myclass.ab.final 最終クラスABの説明 700 1344 1128
myclass.ac.abstract AC抽象クラスの説明 700 1344 1128
myclass.b.extended.empty Aを拡張するクラスBの説明 700 1344 1128
myclass.c.empty.namespace 空の名前空間Cの説明 0 0 0
myclass.d.construct クラスDコンストラクターの説明 1104 2288 1920
myclass.dd.method メソッドを使用したDDクラスの説明 1088 2280 1912
myclass.ddd.private.var プライベート変数を持つDDDクラスの説明 960 1840 1472
myclass.dddd.public.var パブリック変数を持つDDDDクラスの説明 960 1840 1472
myclass.ddddd.static.var 静的変数を持つDDDDDクラスの説明 960 1840 1472
myclass.e.extended.destruct クラスDを拡張するデストラクタを使用したクラスEの説明 1344 2704 2272
myclass.e.instance.ab ABオブジェクトと$ eリンクの作成 264 512 352
myclass.e.instance.ddddd DDDDDオブジェクトと$ eリンクの作成 0 0 0
myclass.e.instance.e オブジェクトEを作成し、$ eにリンクします 0 0 0
myclass.f.instance.ddddd DDDDDオブジェクトと$ fリンクの作成 264 512 352
myclass.z.free_memory リンクの削除$ e、$ f -484 -944 -656
zend.a.init.autoload ZendFrameworkの自動ロードを初期化する 127 444 276,288 249 232
zend.a.init.model ベースのデフォルトアダプターの初期化 1 018 388 2 081 600 1 871 256
zend.extended.controller1 Zend_Controller_Actionからのコントローラー定義。 途中で、標準のZendクラスをロードします 378,296 809 384 712 816
zend.extended.controller2 コントローラーの定義。 Zendクラスは既にロードされています。クラスの重量を確認してください 11 328 19 608 16,008
zend.extended.model1 Zend_Db_Tableによるモデル定義。 途中で、標準Zendクラスのロードが行われます。 27 936 48 544 40 224
zend.extended.model2 モデルの定義。 Zendクラスは既にロードされています。クラスの重量を確認してください 27 936 48 536 40 208
zend.use.model1.e.instance1 Model1オブジェクトと$ eリンクの作成 2492 4648 3432
zend.use.model1.f.instance2 Model1オブジェクトの作成と$ fのリンク 1764 3256 2488
zend.use.model1.g.instance3 Model1オブジェクトと$ gリンクの作成 1764 3256 2488
zend.use.model2.e.instance1 Model2オブジェクトと$ eリンクの作成 740 1400 944
zend.use.model2.f.instance2 Model2オブジェクトと$ f参照の作成 0 0 0




Gentooビルドが消費するメモリが10〜20%少ないことに気付くかもしれません。まれに、最大50%の節約になります。 どうやら、内部構造のサイズはプロセッサの最適化に依存します。 実験のために、さまざまなバージョンのCFLAGSを使用してphpを再構築しましたが、これ以上の消費は開始しませんでした。 どうやら、違いはPHP自体の再構築によるものではなく、標準のCisternライブラリの再構築によるものです。





上記のように、$ include_overheadを正確に測定することは難しいため、これらのテストを実行すると、同じものを消費するテストであっても、4、8、12、16バイトにジャンプするメモリ消費が発生する場合があります。 これに集中しないでください。 テストを異なる順序で実行し、実際のメモリ消費量を設定しました。



ZendFrameworkに関連するテストについて話しましょう。 Zendのクラス定義をメモリにロードすると、リソースが大量に消費されますが、オブジェクト参照はすでにそれほど消費していません。 Controller2は、すべての中間クラスが既にメモリ内にある場合に同様のコントローラーがどれだけ食べるかを確認するために必要です。 Model2は同じ目的で作成されます。

潜在的に、PHPアクセラレータを使用すると、すべての定義のメモリが節約されます。定義は既にメモリに格納されているためです。 このステートメントを確認しましょう。



加速器試験



APCはテスト用に取得され、テストはスクリプトを使用してWeb経由で実行されました。

 php run.testsuite-with-accelerator.php
      
      





結果は、アクセラレータが効果を発揮するテストのみを示しています。

テスト名 説明 Ubuntu x86、

PHP 5.3.10、

ZF 1.11.11、

空のキャッシュ
Ubuntu x86、

PHP 5.3.10、

ZF 1.11.11、

リフレッシュ
Ubuntu x86-64、

PHP 5.3.10、

ZF 1.11.11、

空のキャッシュ
Ubuntu x86-64、

PHP 5.3.10、

ZF 1.11.11、

リフレッシュ
myclass.a.empty クラスAの説明 840 672 1480 1256
myclass.aa.interface インターフェイスの説明A 856 676 1512 1264
myclass.ab.final 最終クラスABの説明 844 672 1488 1256
myclass.ac.abstract AC抽象クラスの説明 852 680 1504 1264
myclass.b.extended.empty Aを拡張するクラスBの説明 912 700 1512 1264
myclass.c.empty.namespace 空の名前空間Cの説明 176 -16 184 -72
myclass.d.construct クラスDコンストラクターの説明 1256 960 2448 1736
myclass.dd.method メソッドを使用したDDクラスの説明 1268 968 2432 1728
myclass.ddd.private.var プライベート変数を持つDDDクラスの説明 1140 964 2000年 1760
myclass.dddd.public.var パブリック変数を持つDDDDクラスの説明 1132 952 2000年 1760
myclass.ddddd.static.var 静的変数を持つDDDDDクラスの説明 1124 952 2000年 1760
myclass.e.extended.destruct クラスDを拡張するデストラクタを持つクラスEの説明 1528 1228 2888 2160
myclass.z.free_memory リンクの削除$ e、$ f -332 -548 -784 -1024
zend.a.init.autoload ZendFrameworkの自動ロードを初期化する 127 596 16 196 276,440 28,992
zend.a.init.model ベースのデフォルトアダプターの初期化 1 018 564 251 840 2 081 696 479,280
zend.extended.controller1 Zend_Controller_Actionからのコントローラー定義。 途中で、標準のZendクラスをロードします 378,464 66 804 809 608 120 864
zend.extended.controller2 コントローラーの定義。 クラスZendはすでにロードされています。クラスの重量を確認します 11 476 11 140 19 792 19 056
zend.extended.model1 Zend_Db_Tableによるモデル定義。 途中で、標準のZendクラスの読み込みが行われます。 28,080 25,676 48,704 42 944
zend.extended.model2 モデルの定義。 Zendクラスは既にロードされています。クラスの重量を確認してください 28,080 25,704 48,672 42 960




また、xcacheでいくつかのテストを行い、APCとの2つの違いに気付きました。 まず、xcacheは(ほとんどの場合)メモリを10〜15%節約します。 次に、xcacheはキャッシュからファイルをすぐに返しますが、APCは繰り返しアクセスした後のみです。 役に立たないが、利点。





すぐに、ファイルの名前が変更されず、$ include_overheadが大きなエラーで計算されたため、結果のばらつきはアクセラレータなしでテストする場合よりもはるかに大きいことに注意してください。



ご覧のように、アクセラレータは定義のためにメモリを節約しますが、PHPがキャッシュから現在のセッションにいくつかのピースを転送するように見えるため、完全ではありません。

次に、抽象的なテストから実際のテストに移りましょう。



ZendFrameworkで小さなアプリケーションをテストする



テストのために、プログラマーの1人( Simple-blog )のテストタスクを行いました。機能は、登録、承認、投稿のリストの読み取り、投稿のオープン、コメント付きの機能を持つ集合ブログサービスです。 index.phpの最後に次のように書かれています:

 echo memory_get_peak_usage();
      
      



ページ生成中にスクリプトが消費したメモリ量を確認します。 結果:

ページの種類 Ubuntu x86、

PHP 5.3.10、

ZF 1.11.11、

空のキャッシュ
Ubuntu x86、

PHP 5.3.10、

ZF 1.11.11、

リフレッシュ
Ubuntu x86-64、

PHP 5.3.10、

ZF 1.11.11、

空のキャッシュ
Ubuntu x86-64、

PHP 5.3.10、

ZF 1.11.11、

リフレッシュ
投稿リスト 5 328 648 1 792 968 10 938 160 3 306 720
投稿とコメント 5 372 356 1 831 452 11 015 320 3 373 528
ログインフォーム 6 781 656 2,277,164 13 982 104 4 187 600
登録フォーム 6 796 496 2,291,568 14 009 384 4 211 432


さらに、Gentooのアセンブリがテストされましたが、すべてのテストで25%の効果が得られました。



結論





コジャラ





UPD



AntonShevchukは 、PHP 5.4のテスト結果を追加しました。 PHP 5.4は5.3よりもはるかに経済的に見えます。 公式文書でもこれが確認されています。



All Articles