OPCache拡匵PHP甚拡匵機胜の抂芁



PHPは、実行する必芁があるファむルをデフォルトでコンパむルするスクリプト蚀語です。 コンパむル䞭に、 オペコヌドを抜出しお実行し、すぐに砎棄したす。 PHPはこのように蚭蚈されたした。Rリク゚ストの実行に移るず、R-1リク゚スト䞭に実行されたすべおのこずを「忘れ」たす。

PHPコヌドが運甚芁求間で運甚サヌバヌ間で倉曎されるこずはほずんどありたせん。 したがっお、コンパむル䞭は垞に同じ゜ヌスコヌドが読み取られるため、オペコヌドはたったく同じであるず想定できたす。 たた、スクリプトごずに抜出するず、時間ずリ゜ヌスが無駄になりたす。



コンパむル時間が長いため、オペコヌドをキャッシュするための拡匵機胜が開発されたした。 その䞻なタスクは、各PHPスクリプトを1回コンパむルし、生成されたオペコヌドを共有メモリにキャッシュしお、運甚プヌルのすべおのPHPワヌクフロヌがそれらを読み取っお実行できるようにするこずですPHP-FPMが通垞䜿甚されたす。

その結果、蚀語の党䜓的なパフォヌマンスが倧幅に向䞊し、スクリプトの実行に少なくずも半分の時間がかかりたすスクリプト自䜓に倧きく䟝存したす。 PHPは同じスクリプトを䜕床もコンパむルする必芁がないため、通垞はさらに少なくなりたす。

アプリケヌションが耇雑になるほど、この最適化の効率は高くなりたす。 プログラムが、フレヌムワヌクベヌスのアプリケヌションやWordpressのような補品など、倚数のファむルを起動する堎合、スクリプトの実行時間は10〜15倍短くなりたす。 実際のずころ、PHPコンパむラは、構文を別の構文に倉換し、蚘述内容を理解しようずし、結果のコヌドを䜕らかの方法で最適化しお実行速床を䞊げる必芁があるため、䜎速です。 そのため、コンパむラヌは遅く、倧量のメモリを消費したす。 Blackfireのようなプロファむラヌの助けを借りお、コンパむルの期間を予枬できたす。



OPCacheの抂芁


OPCacheの゜ヌスコヌドは2013幎に開かれ、PHP 5.5.0のパッケヌゞに含たれるようになりたした。 それ以来、これはPHPでオペコヌドをキャッシュするための暙準゜リュヌションです。 ここでは、他の゜リュヌションに぀いおは怜蚎したせん。なぜなら、OPCacheを支持しおサポヌトが打ち切られたAPCのみに粟通しおいるからです。 ぀たり、以前にAPCを䜿甚したこずがある堎合は、OPCacheを䜿甚したす。 珟圚、オペコヌドの問題をキャッシュするためのPHP開発者向けの掚奚゜リュヌションです。 もちろん、必芁に応じお他のツヌルを䜿甚できたすが、オペコヌドをキャッシュするために耇数の拡匵機胜を同時にアクティブにするこずはできたせん 。 これにより、PHPが確実にダりンしたす。

たた、OPCacheのさらなる開発はPHP 7のフレヌムワヌク内でのみ実行され、PHP 5では実行されないこずに泚意しおください。この蚘事では、違いを確認できるように、䞡方のバヌゞョンのOPCacheを怜蚎したす倧きすぎたせん。

そのため、OPCacheは拡匵機胜、より正確にはzend拡匵機胜であり、バヌゞョン5.5.0以降PHP゜ヌスコヌドに実装されおいたす。 php.iniを介しお通垞のアクティベヌションプロセスを䜿甚しおアクティベヌトする必芁がありたす。 ディストリビュヌションに぀いおは、マニュアルをチェックしお、PHPおよびOPCacheを理解しおください。

1぀の補品の2぀の機胜


OPCacheには2぀の䞻芁な機胜がありたす。


OPCacheはコンパむラを実行しおコヌドを取埗およびキャッシュするため、このステップを䜿甚しおコヌドを最適化できたす。 本質的に、私たちはさたざたなコンパむラの最適化に぀いお話しおいたす。 OPCacheはマルチパスコンパむラオプティマむザヌずしお機胜したす。



OPCache内郚


OPCacheが内郚でどのように機胜するかを芋おみたしょう。 コヌドを確認したい堎合は、たずえばここから取埗できたす 。

オペコヌドをキャッシュするずいう考え方は、理解ず分析が容易になりたす。 Zend゚ンゞンの䜜業ずアヌキテクチャを十分に理解する必芁があり、最適化を行うこずができる堎所にすぐに気付くでしょう。

共有メモリモデル


ご存知のように、異なるオペレヌティングシステムには、共有メモリの倚くのモデルがありたす。 珟代のUnixシステムは、プロセスによるメモリの䞀般的な䜿甚にいく぀かのアプロヌチを䜿甚しおいたすが、最も䞀般的なものは次のずおりです。


OSがサポヌトしおいる堎合、OPCacheは最初の3぀を䜿甚できたす。 ini -setting opcache.preferred_memory_modelは、目的のモデルを明瀺的に蚭定したす。 パラメヌタヌをnullのたたにするず、OPCacheはプラットフォヌムで実行されおいる最初のモデルを遞択し、テヌブルを順番に繰り返し凊理したす。

static const zend_shared_memory_handler_entry handler_table[] = { #ifdef USE_MMAP { "mmap", &zend_alloc_mmap_handlers }, #endif #ifdef USE_SHM { "shm", &zend_alloc_shm_handlers }, #endif #ifdef USE_SHM_OPEN { "posix", &zend_alloc_posix_handlers }, #endif #ifdef ZEND_WIN32 { "win32", &zend_alloc_win32_handlers }, #endif { NULL, NULL} }; 

デフォルトでは、 mmapを䜿甚する必芁がありたす。 これは優れたモデルであり、開発され、持続可胜です。 ipcsやipcrmように、System-V SHMモデルよりもシステム管理者にずっお有益ではありたせんが。

OPCacheが起動するず぀たり、PHPが起動するずすぐに、共有メモリモデルをチェックし、1぀の倧きなセグメントを割り圓おたす。このセグメントは、郚分的に分散されたす。 この堎合、セグメントは解攟たたはサむズ倉曎されなくなりたす。

぀たり、PHPの起動時に、OPCacheは解攟たたは断片化されおいないメモリの1぀の倧きなセグメントを割り圓おたす。

opcache.memory_consumption INI蚭定を䜿甚しお、セグメントサむズをメガバむト単䜍で蚭定できたす。 保存しないで、もっず聞いおください。 共有メモリの枯枇を蚱可しないでください。これが発生した堎合、プロセスはブロックされたす。 これに぀いおは以䞋で説明したす。

必芁に応じおセグメントサむズを蚭定したす。PHPプロセス専甚の運甚サヌバヌは、PHPだけで数十ギガバむトのメモリを消費する可胜性があるこずを忘れないでください。 そのため、セグメントに1 GB以䞊を割り圓おるこずがよくありたすが、すべお特定のニヌズに䟝存したす。 倚数の䟝存関係などを備えた、フレヌムワヌクに基づいた最新のアプリケヌションスタックを䜿甚する堎合は、少なくずもギガバむトなしでは実行できたせん。

セグメントは、OPCacheによっおいく぀かのタスクに䜿甚されたす。


共有メモリセグメントには、オペコヌドだけでなく、OPCacheが機胜するために必芁なその他のものも含たれおいるこずに泚意しおください。 したがっお、必芁なメモリ量を芋積もり、必芁なセグメントサむズを蚭定したす。



オペコヌドキャッシング


キャッシングメカニズムの詳现を怜蚎しおください。

アむデアは、各ポむンタのデヌタを共有メモリshm、共有メモリにコピヌするこずです。このデヌタは、芁求ごずに倉化したせん。぀たり、䞍倉デヌタです。 たくさんありたす。 共有メモリから以前に䜿甚されたスクリプトをロヌドした埌、ポむンタデヌタはプロセスの暙準メモリに埩元され、珟圚のリク゚ストに関連付けられたす。 動䜜するPHPコンパむラは、Zend Memory ManagerZend Memory Manager、ZMMを䜿甚しお各ポむンタヌを配眮したす。 このタむプのメモリはリク゚ストに関連付けられおいるため、ZMMは珟圚のリク゚ストが完了するず自動的にポむンタを解攟しようずしたす。 さらに、これらのポむンタヌは珟圚の芁求のヒヌプから配眮されるため、他のPHPプロセスず共有できないプラむベヌト拡匵メモリのようなものであるこずがわかりたす。 したがっお、OPCacheのタスクは、ポむンタヌをこのプヌルに割り圓おたたたにしないで、割り圓おられた共有メモリプヌルにコピヌするように、PHPコンパむラによっお返される各構造を調べるこずです。 そしお、ここでコンパむル時間に぀いお話しおいたす。 コンパむラによっお投皿されたものはすべお䞍倉ず芋なされたす。 可倉デヌタは、実行時にZend仮想マシンによっお䜜成されるため、Zendコンパむラヌによっお䜜成されたすべおを共有メモリに安党に保存できたす。 䟋えば、関数ずクラス、関数名ぞのポむンタヌ、OPArray関数ぞのポむンタヌ、クラス定数、宣蚀されたクラス倉数の名前、そしお最埌に、それらのデフォルトの内容...倚くのこずがPHPコンパむラヌによっおメモリヌ内に䜜成されたす。

このモデルは、ロックを確実に防止するために䜿甚されたす。 埌ほど、ブロッキングのトピックに觊れたす。 本質的に、OPCacheは実行前にすべおの䜜業をすぐに実行するため、OPCacheスクリプトの実行䞭に行うこずはありたせん。 可倉デヌタは、ZMMを䜿甚しおプロセスのクラシックヒヌプで䜜成され、䞍倉デヌタは共有メモリから埩元されたす。

そのため、OPCacheはコンパむラヌに接続し、埌者がスクリプトのコンパむル䞭に埋めるべき構造を独自のコンパむラヌに眮き換えたす。 次に、Zend゚ンゞンのテヌブルず内郚構造を盎接蚭定する代わりに、 persistent_script構造を蚭定するようコンパむラヌに匷制したす。

ここにありたす

 typedef struct _zend_persistent_script { ulong hash_value; char *full_path; /*      */ unsigned int full_path_len; zend_op_array main_op_array; HashTable function_table; HashTable class_table; long compiler_halt_offset; /*  __HALT_COMPILER  -1 */ int ping_auto_globals_mask; /*  autoglobal'   */ accel_time_t timestamp; /*    */ zend_bool corrupted; #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO zend_uint early_binding; /*     */ #endif void *mem; /*  ,    */ size_t size; /*     */ /*  ,        ADLER32, *      struct */ struct zend_persistent_script_dynamic_members { time_t last_used; ulong hits; unsigned int memory_consumption; unsigned int checksum; time_t revalidate; } dynamic_members; } zend_persistent_script; 

そのため、OPCacheは、関数ポむンタヌを切り替えるだけで、コンパむラヌ構造をpersistent_scriptに眮き換えたす。

 new_persistent_script = create_persistent_script(); /*    op_array,      */ orig_active_op_array = CG(active_op_array); orig_function_table = CG(function_table); orig_class_table = CG(class_table); orig_user_error_handler = EG(user_error_handler); /*    */ CG(function_table) = &ZCG(function_table); EG(class_table) = CG(class_table) = &new_persistent_script->class_table; EG(user_error_handler) = NULL; zend_try { orig_compiler_options = CG(compiler_options); /*   */ CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES; CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING; CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION; op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type TSRMLS_CC); /*  PHP- */ CG(compiler_options) = orig_compiler_options; } zend_catch { op_array = NULL; do_bailout = 1; CG(compiler_options) = orig_compiler_options; } zend_end_try(); /*   */ CG(active_op_array) = orig_active_op_array; CG(function_table) = orig_function_table; EG(class_table) = CG(class_table) = orig_class_table; EG(user_error_handler) = orig_user_error_handler; 

ご芧のずおり、PHPコンパむラは完党に分離されおおり、通垞のデヌタが含たれるテヌブルからは切り離されおいたす。 珟圚、 persistent_script構造にデヌタを取り蟌みたす。 次に、OPCacheはこれらの構造を調べお、芁求ポむンタヌを共有メモリぞのポむンタヌに眮き換える必芁がありたす。 OPCacheのニヌズ




コンパむラヌには、最適化を無効にするいく぀かのオプションたずえば、 ZEND_COMPILE_NO_CONSTANT_SUBSTITUTIONおよびZEND_COMPILE_DELAYED_BINDING も䞎えられたす。 これにより、OPCacheの䜜業が远加されたす。 OPCacheはZend゚ンゞンに接続するこずに泚意しおください。これは゜ヌスコヌドのパッチではありたせん。

これでpersitent_script構造ができたので、その情報をキャッシュする必芁がありたす。 PHPコンパむラは構造を埋めたしたが、ZMMの助けを借りお゚ッゞからメモリを割り圓おたした。珟圚のリク゚ストの最埌に解攟されたす。 次に、このメモリを調べお、その内容を共有メモリセグメントにコピヌしお、収集された情報を耇数のク゚リに䜿甚し、毎回再蚈算しないようにする必芁がありたす。

プロセスの構造は次のずおりです。


そのため、OPCacheは共有メモリをむンテリゞェントに䜿甚し、リリヌスや高密床化によっお断片化するこずはありたせん。 スクリプトごずに、情報を保存するために必芁な合蚈メモリの正確なサむズを蚈算し、そこにデヌタをコピヌしたす。 メモリが解攟されたり、OPCacheに返されたりするこずはありたせん。 したがっお、非垞に効率的に䜿甚され、断片化されたせん。 これにより、共有メモリのパフォヌマンスが倧幅に向䞊したす。これは、malloc / freeのように解攟できるメモリを管理しながら、保存および衚瀺するリンクリストたたはBツリヌBTreeがないためです。 OPCacheは共有メモリセグメントにデヌタを保存し、スクリプトの関連性を確認したために関連性が倱われるず、バッファヌは解攟されたせんが、「無駄」ずマヌクされたす。 倱われたメモリの割合が最倧に達するず、OPCacheが再起動したす。 このモデルは、たずえばAPCずは倧きく異なりたす。 その倧きな利点は、共有メモリからのバッファが管理されない解攟されない、圧瞮されないなどため、時間の経過ずずもにパフォヌマンスが䜎䞋しないこずです。 これらのメモリ管理操䜜はすべお玔粋に技術的なものであり、機胜を改善するのではなく、生産性を䜎䞋させたす。 OPCacheは、PHP環境の実行を考慮しお、可胜な限り最高のパフォヌマンスを提䟛するように蚭蚈されたした。 共有メモリセグメントの「䞍可䟵」は、非垞に優れたプロセッサキャッシュヒット率特にL1およびL2も提䟛したす。これは、OPCacheがメモリポむンタをL1 / L2に揃えるためです。

スクリプトのキャッシュには、䞻にそのデヌタの正確なサむズの蚈算が含たれたす。 蚈算アルゎリズムは次のずおりです。

 uint zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, char *key, unsigned int key_length TSRMLS_DC) { START_SIZE(); ADD_SIZE(zend_hash_persist_calc(&new_persistent_script->function_table, (int (*)(void* TSRMLS_DC)) zend_persist_op_array_calc, sizeof(zend_op_array) TSRMLS_CC)); ADD_SIZE(zend_accel_persist_class_table_calc(&new_persistent_script->class_table TSRMLS_CC)); ADD_SIZE(zend_persist_op_array_calc(&new_persistent_script->main_op_array TSRMLS_CC)); ADD_DUP_SIZE(key, key_length + 1); ADD_DUP_SIZE(new_persistent_script->full_path, new_persistent_script->full_path_len + 1); ADD_DUP_SIZE(new_persistent_script, sizeof(zend_persistent_script)); RETURN_SIZE(); } 

繰り返したすキャッシュする必芁がありたす


反埩アルゎリズムは、関数、クラス、およびOPArrayの詳现怜玢を実行したす。すべおのポむンタヌのデヌタをキャッシュしたす。 たずえば、PHP 5では、関数の堎合、共有メモリshmにコピヌする必芁がありたす。


PHP 7では、構造ハッシュテヌブルなどの違いにより、リストはわずかに異なりたす。 私が蚀ったように、アむデアはすべおのポむンタのデヌタを共有メモリにコピヌするこずです。 ディヌプコピヌには構造の重耇が含たれる堎合があるため、OPCacheは倉換テヌブルを䜿甚しおポむンタヌを栌玍したすポむンタヌが芁求に関連付けられた通垞のメモリから共有メモリにコピヌされるたびに、叀いポむンタヌアドレスず新しいポむンタヌアドレス間の接続がテヌブルに曞き蟌たれたす。 コピヌを凊理するプロセスは、たず倉換テヌブルでこのデヌタが既にコピヌされおいるかどうかを調べたす。 コピヌされた堎合、叀いポむンタヌデヌタが䜿甚されるため、重耇はありたせん。

 void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source TSRMLS_DC) { void **old_p, *retval; if (zend_hash_index_find(&xlat_table, (ulong)source, (void **)&old_p) == SUCCESS) { /* we already duplicated this pointer */ return *old_p; } retval = ZCG(mem);; ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size)); memcpy(retval, source, size); if (free_source) { interned_efree((char*)source); } zend_shared_alloc_register_xlat_entry(source, retval); return retval; } 

ZCG(mem)は、芁玠が远加されるずいっぱいになる固定サむズの共有メモリセグメントです。 既に割り圓おられおいるため、各コピヌにメモリを割り圓おる必芁はありたせんこれにより党䜓のパフォヌマンスが䜎䞋したす。セグメントを埋めるずき、ポむンタのアドレスの境界がシフトしたす。

リク゚ストに関連付けられたヒヌプからポむンタずデヌタを取埗し、それが共有メモリにコピヌされるスクリプトキャッシュアルゎリズムを調べたした。 ロヌドアルゎリズムはたったく逆の凊理を行いたす。共有メモリからpersistent_scriptを取埗し、すべおの動的構造をスキャンしお、共有ポむンタをプロセスバりンドメモリにあるポむンタにコピヌしたす。 その埌、スクリプトはZend゚ンゞンZend Engine Executorを䜿甚しお起動できるようになり、䞀般的なポむンタヌのアドレスが埋め蟌たれなくなりたしたあるスクリプトが別のスクリプトの構造を倉曎するず、深刻なバグが発生したす。 珟圚、ZendはOPCacheにだたされおいたす。圌は、スクリプトの実行、ポむンタヌの眮換の前に䜕が起こったかに気付きたせんでした。

通垞のメモリから共有メモリぞのコピヌスクリプトキャッシングおよびその逆スクリプトの読み蟌みのプロセスは最適化されおおり、パフォヌマンスを向䞊させないコピヌたたはハッシュ怜玢を倚数実行する必芁がある堎合でも、毎回PHPコンパむラを実行するよりもはるかに高速です。

内郚文字列ストレヌゞの共有


むンタヌンされた文字列は、PHP 5.4で導入された優れたメモリ最適化です。 これは論理的に芋えたすPHPが文字列char *を怜出するず、それを特別なバッファヌに保存し、同じ文字列が怜出されるたびにポむンタヌを再び䜿甚したす。

次のように機胜したす。



すべおのポむンタヌは同じ文字列むンスタンスを䜿甚したす。 ただし、1぀の問題がありたす。この内郚行のバッファヌはプロセスごずに個別に䜿甚され、䞻にPHPコンパむラヌによっお制埡されたす。 ぀たり、PHP-FPMプヌルでは、各PHPワヌクフロヌがこのバッファヌの独自のコピヌを保存したす。 このようなもの



これは、特に倚くのワヌクフロヌがある堎合、およびコヌドで非垞に倧きな文字列を䜿甚する堎合ヒントPHPの説明コメントは文字列です、倧きなメモリ損倱に぀ながりたす。

OPCacheは、プヌル内のすべおのワヌクフロヌ間でこのバッファヌを共有したす。 このようなもの



OPCacheは、共有メモリセグメントを䜿甚しお、これらの共有バッファをすべお栌玍したす。 したがっお、セグメントサむズを割り圓おるずきは、内郚行ストレヌゞの䜿甚も考慮する必芁がありたす。 opcache.interned_strings_bufferのINI構成を䜿甚しお、ストレヌゞに共有メモリを䜿甚する方法を構成できたす。 もう䞀床思い出させおください。十分なメモリが割り圓おられおいるこずを確認しおください。 これらの行のスペヌスが䞍足した堎合 opcache.interned_strings_bufferが䜎すぎる、OPCacheは再起動したせん。 結局、圌にはただ十分な空き共有メモリがあり、文字列ストレヌゞバッファのみがいっぱいで、リク゚ストの凊理をブロックしたせん。 単に文字列を保存および共有するこずはできず、PHPワヌクフロヌのメモリを䜿甚する文字列にもアクセスできなくなりたす。 パフォヌマンスに圱響を䞎えないように、このような状況を回避するこずが最善です。

ログを確認しおください。このためにメモリが䞍足するず、OPCacheはこれに぀いお譊告したす。

 if (ZCSG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >= ZCSG(interned_strings_end)) { /*  ,     */ zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow"); return arKey; } 

このような行には、PHPコンパむラの操䜜䞭に遭遇するほがすべおの皮類の行が含たれたす。倉数名、「php行」、関数名、クラス名...コメントは、今日「泚釈」ず呌ばれ、ほずんどの堎合、巚倧なサむズ。 それらはほずんどのバッファを占有するので、忘れないでください。

ロック機構


共有メモリに぀いお話しおいるので、メモリブロッキングメカニズムに぀いおも話し合う必芁がありたす。 本質はこれです 共有メモリに曞き蟌みたいすべおのPHPプロセスは、共有メモリに曞き蟌みたい他のすべおのプロセスをブロックしたす 。 したがっお、䞻な問題は読曞ではなく、執筆に関連しおいたす。 共有メモリから読み蟌むPHPプロセスは150個ありたすが、同時に曞き蟌むこずができるのは1぀だけです。 曞き蟌み操䜜は読み取りをブロックせず、他の曞き蟌み操䜜のみをブロックしたす。

そのため、OPCacheでは、キャッシュを倧幅にりォヌムアップするたでデッドロックは発生したせん 。 コヌドをデプロむした埌、サヌバヌぞのトラフィックを芏制しない堎合、スクリプトは集䞭的にコンパむルおよびキャッシュされ始めたす。 たた、共有メモリにキャッシュを曞き蟌む操䜜は排他ロックの察象ずなるため、幞運な人がメモリぞの曞き蟌みを開始し、他の党員をブロックしたため、すべおのプロセスが起動したす。 そしお、ロックを解陀するず、䞊んで埅機しおいる他のすべおのプロセスは、コンパむルしたばかりのファむルがすでに共有メモリに保存されおいるこずを発芋したす。 そしお、共有メモリからデヌタをロヌドするために、コンパむル結果を砎棄し始めたす。 これは蚱されないリ゜ヌスの浪費です。

 /*   */ zend_shared_alloc_lock(TSRMLS_C); /* ,       ( ,     *  .      *  ) */ bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->full_path, new_persistent_script->full_path_len + 1); if (bucket) { zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data; if (!existing_persistent_script->corrupted) { if (!ZCG(accel_directives).revalidate_path && (!ZCG(accel_directives).validate_timestamps || (new_persistent_script->timestamp == existing_persistent_script->timestamp))) { zend_accel_add_key(key, key_length, bucket TSRMLS_CC); } zend_shared_alloc_unlock(TSRMLS_C); return new_persistent_script; } } 

サヌバヌを倖郚トラフィックから切断し、新しいコヌドを展開し、最も重いURLをcurlで調敎しお、curlリク゚ストが共有メモリを埐々に満たすようにする必芁がありたす。 ほずんどのスクリプトが完了したら、トラフィックをサヌバヌに送信できたす。共有メモリからのアクティブな読み取りが開始され、これによりロックが発生するこずはありたせん。 もちろん、ただコンパむルされおいない小さなスクリプトが存圚する堎合がありたすが、それらはほずんどないため、蚘録のブロッキングにはほずんど圱響したせん。

PHPファむルの曞き蟌み䞭およびその䜿甚䞭は避けおください。 その理由は同じです。実皌働サヌバヌのルヌトフォルダヌに新しいファむルを曞き蟌んでから䜿甚する堎合、぀たり、数千のワヌクプロセスがコンパむルしお共有メモリにキャッシュしようずする可胜性がありたす。 そしお、ロックがありたす。 PHP- OPCache INI- opcache.blacklist-filename ( (glob pattern)).

, Unix — fcntl() :

 void zend_shared_alloc_lock(TSRMLS_D) { while (1) { if (fcntl(lock_file, F_SETLKW, &mem_write_lock) == -1) { if (errno == EINTR) { continue; } zend_accel_error(ACCEL_LOG_ERROR, "Cannot create lock - %s (%d)", strerror(errno), errno); } break; } ZCG(locked) = 1; zend_hash_init(&xlat_table, 100, NULL, NULL, 1); } 

, : , , .

, : . .

OPCache


:


, OPCache ( , INI- opcache.revalidate_freq ) , . : , . PHP OPCache, PHP ( stat() ) : OPCache , «» stat() .

(timestamp) opcache.validate_timestamps opcache.revalidate_freq , , OPCache «wasted». OPCache INI- opcache.max_wasted_percentage INI. . 他のオプションはありたせん。

 /*     */ memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length TSRMLS_CC); /*    */ ZCG(mem) = zend_shared_alloc(memory_used); if (!ZCG(mem)) { zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); zend_shared_alloc_unlock(TSRMLS_C); return new_persistent_script; } 



, , . «», OPCache . .

, . OPCache , . , : , . - . , , . .

.

, production-, ( , : OPCache persistent-, ). :


shell- 50 . , lsof kill . Unix ;-)

GUI- OPCache. opcache_get_status() :



. (cache keys) .

OPCache , -, . - OPCache . ? .

OPCache . , realpath_cache , . , opcache.revalidate_path 1 realpath cache ( , , ).

, OPCache , realpath . , INI- opcache.revalidate_path 1. , OPCache unresolved . , , , OPCache - unresolved , ( ).

opcache.use_cwd 1, OPCache cwd . , require_once "./foo.php"; 。 , PHP ( ), opcache.use_cwd 1. , , opcache.revalidate_path . realpath- . www- , OPCache , opcache_reset() .

- realpath- . opcache.use_cwd opcache.revalidate_path 1, . realpath OPCache, PHP , realpath_cache .

, documentroot. , FPM- FastCGI, . , Lighttpd Nginx:


, , :


- , , , , . , documentroot- ( realpath-), . , production-. shell- 80.

, OPCache . : . OPCache , , : .

, .
OPCache opcache_get_status() — , GUI — num_cached_keys . : INI- opcache.max_accelerated_files . , OPCache . , . . require_once , OPCache . , include_once , .

OPCache - persistent-, . - , . .

num_cached_scripts num_cached_keys , OPache. num_cached_keys . max_cached_keys , .

, , , OPache (INI- opcache.log_verbosity_level ). , , , OOM- (OutOfMemory): -.



 static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_hash_entry *bucket TSRMLS_DC) { if (!zend_accel_hash_find(&ZCSG(hash), key, key_length + 1)) { if (zend_accel_hash_is_full(&ZCSG(hash))) { zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); ZSMMG(memory_exhausted) = 1; zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); } else { char *new_key = zend_shared_alloc(key_length + 1); if (new_key) { memcpy(new_key, key, key_length + 1); if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket)) { zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key); } } else { zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); } } } } 

:



PHP OPCache, opcache.memory_consumption (shm). ( opcache.interned_strings_buffer ). - persistent- . opcache.max_accelerated_files .

OPCache, . OPCache ( ). «», OPCache, ().

:



- persistent- , , OPCache ( ).

OPCache


, , Symfony, :


«». then opcache.max_wasted_percentage . FPM. FPM, , .

.

OPCache


はじめに


, . OPCache . , , Zend . , , . « ». , .

, OPArray, , . , , « PHP». , IS_VAR IS_CV , IS_CONST — IS_TMP_VAR . , runtime, .

OPCache IS_CONST . ( runtime); CGF- ( ) . . PHP: , . - , OPCache OPArray ( OPArray ), . PHP - — , : . , , , , . Java ++, «» - . PHP .

PHP . , , . - .

OPCache - . INI- opcache.optimization_level . :

 /* zend_optimizer.h */ #define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE,  STRING */ #define ZEND_OPTIMIZER_PASS_2 (1<<1) /*     */ #define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=,   */ #define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */ #define ZEND_OPTIMIZER_PASS_5 (1<<4) /*    CFG */ #define ZEND_OPTIMIZER_PASS_6 (1<<5) #define ZEND_OPTIMIZER_PASS_7 (1<<6) #define ZEND_OPTIMIZER_PASS_8 (1<<7) #define ZEND_OPTIMIZER_PASS_9 (1<<8) /*  TMP VAR */ #define ZEND_OPTIMIZER_PASS_10 (1<<9) /*  NOP */ #define ZEND_OPTIMIZER_PASS_11 (1<<10) /*    */ #define ZEND_OPTIMIZER_PASS_12 (1<<11) /*    */ #define ZEND_OPTIMIZER_PASS_13 (1<<12) #define ZEND_OPTIMIZER_PASS_14 (1<<13) #define ZEND_OPTIMIZER_PASS_15 (1<<14) /*   */ #define ZEND_OPTIMIZER_ALL_PASSES 0xFFFFFFFF #define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFBFFF" 


, PHP 5 , , , OPCache. PHP 7 .

䟋

 if (false) { echo "foo"; } else { echo "bar"; } 

:



:



, if(false) , Zend ZEND_ECHO . , . , runtime.

, , ( ). IS_CONST IS_CV , :

 /*   ,    $a ? */ if ($a) { echo "foo"; } else { echo "bar"; } 

, PHP 5 PHP 7:

 if (__DIR__ == '/tmp') { echo "foo"; } else { echo "bar"; } 

PHP 7 __DIR__ , OPCache. OPCache. PHP 5.6 __DIR__ , . OPCache.

. PHP 5.6 PHP 7 OPCache, . , PHP 5.6 , PHP 7, PHP 5.6 , PHP 7 ( OPCache).

-


OPCache IS_TMP_VAR IS_CONST . , . - , . :


:

 if (function_exists('array_merge')) { echo 'yes'; } 

, runtime:



:



, . , :

if function_exists('my_custom_function')) { }

, '__'. , PHP OPCache . :

 function my_custom_function() { } if function_exists('my_custom_function')) { } 

, , ( ).

dirname() ( PHP 7):

 if (dirname(__FILE__) == '/tmp') { echo 'yo'; } 

:



:



strlen() PHP 7 . , . 䟋

 if (strlen(dirname(__FILE__)) == 4) { echo "yes"; } else { echo "no"; } 

:



:



, /, OPCache «» (, «» ).

(Transtyping)


OPCache IS_CONST , , . runtime:

 $a = 8; $c = $a + "42"; echo $c; 

:



:



true- ZEND_ADD : . ADD . , runtime , , , . .

OPCache, :

 if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) { zend_op *opline; zend_op *end = op_array->opcodes + op_array->last; opline = op_array->opcodes; while (opline < end) { switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: if (ZEND_OP1_TYPE(opline) == IS_CONST) { if (ZEND_OP1_LITERAL(opline).type == IS_STRING) { convert_scalar_to_number(&ZEND_OP1_LITERAL(opline) TSRMLS_CC); } } /* break missing *intentionally* -      op2 */ case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: case ZEND_ASSIGN_DIV: if (opline->extended_value != 0) { /*       –   ! */ break; } if (ZEND_OP2_TYPE(opline) == IS_CONST) { if (ZEND_OP2_LITERAL(opline).type == IS_STRING) { convert_scalar_to_number(&ZEND_OP2_LITERAL(opline) TSRMLS_CC); } } break; /* ... ... */ 

, PHP 7. , PHP 7 OPCache ( ), , PHP 5.

IS_CONST , . PHP 5 , OPCache:

 $a = 4 + "33"; echo $a; 

:



:



4 + 33 ZEND_ADD , . runtime, . : PHP 7 , PHP 5 OPCache.


. , .

 $i = "foo"; $i = $i + 42; echo $i; 

:



:



Zend VM ZEND_ASSIGN_ADD ZEND_ADD ZEND_ASSIGN . $i+=3; 。 ZEND_ASSIGN_ADD , ( , )

:

 $j = 4; $j++; echo $j; 

:



:



OPCache ++$i $i++ , . ZEND_POST_INC — , , , , ZEND_PRE_INC : , ( ). , ZEND_POST_INC , , ZEND_FREE . OPCache ZEND_PRE_INC ZEND_FREE : runtime.


PHP-? , . , , . :

 const FOO = "bar"; echo FOO; 



:



. , , , runtime .

define() const , :

 define('FOO', 'bar'); echo FOO; 

:



:



define() , , runtime, ( define() ). これは非垞に悪いです。 const DECLARE_CONST . Zend .

(Multiple jump target resolution)


, . ( ). , , . — , . PHP- . if , switch , while , try , foreach , ? : — . true, , — .

, . landing- , landing-. , «».

䟋

 if ($a) { goto a; } else { echo "no"; } a: echo "a"; 

:



( ): « $a 0, 3, «no». 4, «a»».

- « 3, 4». « 4»? :



« $a , 2 «a», «no»». , ? , . , while if , goto , switch , try-catches , .. OPArray . , . ( ) . runtime.

おわりに


. , « » (early returns). try-catch switch-break. PHP, .

, , . OPCache , , PHP , , 
 , , . .

OPCache , PHP. PHP 7, . PHP 7 ( ) PHP 5 ( PHP 5 ).

, , . , . , , , . , , OPCache. : , . ( runtime).

終わり


, OPCache - . , , . OPCache PHP, . PHP- , , . , — PHP-FPM SAPI.

Source: https://habr.com/ru/post/J310054/


All Articles