PHP5.3バージョンの前に、可変回復機構PHPは単に処理計数により(参照カウント= 0は、メモリを再利用する場合)、これは問題になります
$ A =配列( "STR");
[] =&$ $。
設定を解除($ A)。
PHPスクリプトが割り当てを完了した後に解除実行する前に、もちろん、すなわち廃棄物、それが0に等しくないので、解除、$ Aは、refcout 1で行った後、メモリを回収することができない、2の参照カウントを$メモリはすべてリサイクルし、今PHPスクリプトに加えて使用、デーモンのサービスを記述するためのより多くの場所(もちろん、私はお勧めしません)、この期間中にこのような上記の方法として、2ヶ月スクリプトの終了前に、月までかかることがありますこれは、メモリのオーバーフローが生成されます
注意:設定を解除し、メモリを解放することはできません、あなたはzvalを参照カウントを見て0ている必要があります
GCのガベージコレクションによって後でPHP5.3
zvalを割り当てる際、単位zval_gc_infoします
#define ALLOC_ZVAL(Z)\ {行う\ (Z)=(zvalを*)におけるemalloc(はsizeof(zval_gc_info))。\ GC_ZVAL_INIT(Z)。\ }(0)、一方 のtypedef構造体_zval_gc_info { zvalをZ。 組合{ gc_root_buffer *バッファリング。 次の* _zval_gc_info構造体。 } U。 } zval_gc_info。 #define FREE_ZVAL(Z)\ ん{\ GC_REMOVE_ZVAL_FROM_BUFFER(Z)。\ efree(Z)。\ }(0)、一方
構造体_gc_root_buffer {typedefは 、構造体_gc_root_buffer * PREV / *二重リンクリスト* / 次のstruct _gc_root_buffer *; zend_object_handleハンドル; / *のzval * / 0でなければならない 組合{ PZ * zvalを。 zend_object_handlers *ハンドラ。 } U。 } gc_root_buffer。
PHPのGC回復メカニズムが起動したとき、それは万gc_root_bufferのスペースを割り当て
ZEND_APIボイドgc_init(TSRMLS_D) { IF(GC_G(BUF)== NULL && GC_G(gc_enabled)){ GC_G(BUF)=(gc_root_buffer *)はmalloc(はsizeof(gc_root_buffer)* GC_ROOT_BUFFER_MAX_ENTRIES)。 GC_G(last_unused)=&GC_G(BUF)GC_ROOT_BUFFER_MAX_ENTRIES]。 gc_reset(TSRMLS_C)。 } }
場合解除($ A)、ここで詳述 キーはzvalをactive_systom_tableで発見された後、zvalを参照カウント-1であった、その値デストラクタを実行する、1の値は、減算後0である場合、即時放出を説明することができますメモリ、それは場所で、0より大きい場合gc_root_buffer
ZEND_APIボイド_zval_ptr_dtor(zvalを** zval_ptr ZEND_FILE_LINE_DC)/ * {{{* / { Z_DELREF_PP(zval_ptr)。 IF(Z_REFCOUNT_PP(zval_ptr)== 0){ TSRMLS_FETCH()。 (!* zval_ptr =&EG(uninitialized_zval)){もし GC_REMOVE_ZVAL_FROM_BUFFER(* zval_ptr)。 zval_dtor(* zval_ptr)。 efree_rel(* zval_ptr)。 } }他{ TSRMLS_FETCH()。 IF(Z_REFCOUNT_PP(zval_ptr)== 1){ Z_UNSET_ISREF_PP(zval_ptr)。 } GC_ZVAL_CHECK_POSSIBLE_ROOT(* zval_ptr)。 } }
#define GC_ZVAL_CHECK_POSSIBLE_ROOT(Z)/ gc_zval_check_possible_root((Z)TSRMLS_CC) 静的zend_always_inline空隙gc_zval_check_possible_root(zvalを* Z TSRMLS_DC) { IF(Z->タイプ== IS_ARRAY || Z->入力== IS_OBJECT){ gc_zval_possible_root(Z軸TSRMLS_CC) ; } } ZEND_API空隙gc_zval_possible_root(zvalを* ZV TSRMLS_DC) { IF(UNEXPECTED(GC_G(free_list)!= NULL && GC_ZVAL_ADDRESS(ZV)!= NULL && GC_ZVAL_GET_COLOR(ZV)== GC_BLACK)&& (GC_ZVAL_ADDRESS(ZV)<GC_G(BUF )|| GC_ZVAL_ADDRESS(ZV)> = GC_G(last_unused))){ / *ザ・のごみはzvalのがあることを行っによって削除されることを考えるとIS GC * /実行されている現在* ;リターンを } IF(zv->タイプ== IS_OBJECT){ ; GC_ZOBJ_CHECK_POSSIBLE_ROOT(ZV) リターン; } GC_BENCH_INC(zval_possible_root); //最後の二つが紫でない場合はZV gc_root_buffer、その後、処理された IF(GC_ZVAL_GET_COLOR(ZV)= GC_PURPLE!){ GC_ZVAL_SET_PURPLE(ZV); //設定紫 IF {(!GC_ZVAL_ADDRESS(ZV)) gc_root_buffer * = newRootトGC_G( )未使用; IF(newRootト){ GC_G(未使用)= newRoot-> PREV; !}そうでなければ(GC_G(first_unused IF)= GC_G(last_unused)){ newRootト= GC_G(first_unused)。 GC_G(first_unused)++; }他{ (!GC_G(gc_enabled))なら、{ GC_ZVAL_SET_BLACK(ZV)。 返します。 } zv-> refcount__gc ++。 gc_collect_cycles(TSRMLS_C)。 zv-> refcount__gc--。 newRootト= GC_G(未使用)。 (!newRootト){もし 返します。 } GC_ZVAL_SET_PURPLE(ZV)。 GC_G(未使用)= newRoot-> PREV。 } newRoot->次= GC_G(根).next。 newRoot-> PREV =&GC_G(ルーツ); GC_G(根).next-> PREV = newRootト。 GC_G(根).next = newRootト。 GC_ZVAL_SET_ADDRESS(ZV、newRootト)。//将gc_root_buffer放到zval_gc_info结构体中 newRoot->ハンドル= 0; newRoot-> u.pz = ZV。 GC_BENCH_INC(zval_buffered)。 GC_BENCH_INC(root_buf_length)。 GC_BENCH_PEAK(root_buf_peak、root_buf_length)。 } } }
gc_root_buferに現在のzvalを、それぞれがzval_gc_infoにzvalの色gc_root_bufferが紫に位置するかどうかに基づいて、一度だけ入れZVAL
#define GC_ZVAL_GET_COLOR(V)\
GC_GET_COLOR(((zval_gc_info *)(V)) - > u.buffered)
#define GC_GET_COLOR(V)\
(((zend_uintptr_t)(V))&GC_COLOR)
それは紫である場合には、紫へ
#define GC_ZVAL_SET_PURPLE(V)\
GC_SET_PURPLE(((zval_gc_info *)(V)) - > u.buffered)
#define GC_SET_PURPLE(V)\
(V)=((gc_root_buffer *)(((zend_uintptr_t)(V))| GC_PURPLE))
マクロGC_ZVAL_SET_ADDRESS(ZV、newRootト); gc_root_buffer newRootトは、対応する位置ZVを配置するために使用
#define GC_COLOR 0x03の に#define GC_BLACKは0x00 の#define GC_WHITEが0x01 の#define GC_GREY 0x02の に#define GC_PURPLE 0x03の に#define GC_ZVAL_SET_ADDRESS(V、A)\ GC_SET_ADDRESS(((zval_gc_info *)(V)) - > u.buffered、(a)参照) #define GC_SET_ADDRESS(V、A)\ (V)=((gc_root_buffer *)((((zend_uintptr_t)(V))&GC_COLOR)|((zend_uintptr_t)(A))))
メモリを割り当てるときGC_ZVAL_SET_ADDRESSマクロvがzval_gc_info最初のタイプに押し込ま、それ自体はzvalを、唯一zvalをパディングデータ構造ので、強いのzvalの*に、ユニットをzval_gc_infoすることであり、これはgc_root_buffer必要はない* buferメンバーのよう
zval_gc_val構造、zvalをZの最初のメンバーは、Zは、メモリアドレスは、アドレス自体zval_gc_infoあるため、
廃棄物処理を示すために色を使用してPHP GCで
32ビットマシンまたは64ビットマシンの両方にポインタを最後の二つは0で、
廃棄物処理をgc_collect_cycles
ZEND_APIのint型gc_collect_cycles(TSRMLS_D) { int型のカウント= 0; {(!GC_G(根)は=&GC_G(根).next)場合 zval_gc_info * P、Q *、* orig_free_list、* orig_next_to_free。 (GC_G(gc_active))なら、{ 0を返します。 } GC_G(gc_runs)++; GC_G(zval_to_free)= FREE_LIST_END。 GC_G(gc_active)= 1。 gc_mark_roots(TSRMLS_C)。 gc_scan_roots(TSRMLS_C)。 gc_collect_roots(TSRMLS_C)。 orig_free_list = GC_G(free_list)。 orig_next_to_free = GC_G(next_to_free)。 P = GC_G(free_list)= GC_G(zval_to_free)。 GC_G(zval_to_free)= NULL; GC_G(gc_active)= 0。 / *最初の呼び出しデストラクタ* / ながら(P!= FREE_LIST_END){ IF(Z_TYPE(P-> Z)== IS_OBJECT){ IF(EG(objects_store).object_buckets && EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。有効&& EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。bucket.obj.refcount <= 0 && EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。bucket.obj .dtor && !EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)] destructor_called){。 EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)] = 1 destructor_called。 EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)] bucket.obj.refcount ++。 EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。bucket.obj.dtor(EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。bucket.obj.object、Z_OBJ_HANDLE(P-> Z )TSRMLS_CC)。 EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)] bucket.obj.refcount--。 } } ++数えます。 P = P - > u.next。 } / * zvalsを破棄* / P = GC_G(free_list)。 一方、(P = FREE_LIST_END!){ GC_G(next_to_free)= P-> u.next。 IF(Z_TYPE(P-> Z)== IS_OBJECT){ IF(EG(objects_store).object_buckets && EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。有効&& EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)]。bucket.obj.refcount <= 0){ EG(objects_store).object_buckets [Z_OBJ_HANDLE(P-> Z)] = 1 bucket.obj.refcount。 Z_TYPE(P-> Z)= IS_NULL。 zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(P-> Z)、Z_OBJ_HT(P-> Z)TSRMLS_CC)。 } }そうであれば(Z_TYPE(P-> Z)== IS_ARRAY){ Z_TYPE(P-> Z)= IS_NULL。 zend_hash_destroy(Z_ARRVAL(P-> Z))。 FREE_HASHTABLE(Z_ARRVAL(P-> }他{ zval_dtor(&P-> Z)。 Z_TYPE(P-> Z)= IS_NULL。 } P = GC_G(next_to_free)。 } / *フリーzvals * / P = GC_G(free_list)。 一方、(P = FREE_LIST_END!){ Q = P-> u.next。 FREE_ZVAL_EX(&P-> Z)。 P = Q。 } GC_G(収集)+ =数えます。 GC_G(free_list)= orig_free_list。 GC_G(next_to_free)= orig_next_to_free。 } カウントを返します。 }
gc_mark_roots(TSRMLS_C);スパムアレイのu.pz各要素は1-れる参照カウント、,. ZVAL横断u.pz灰色に紫色に変化した色マーカー、トラバースgc_root_buffer、レイ
参照カウント=場合、gc_collect_rootsトラバースgc_root_bufferを参照カウント> 0は、誰かが黒に設定し、使用することができる示している場合= 0次いで、白に設定では、スパムとして表さ
静的ボイドgc_mark_roots(TSRMLS_D) { gc_root_buffer *電流= GC_G(根).next。 しばらく(現在!=&GC_G(根)){ 場合(電流- >ハンドル){ 場合(EG(objects_store).object_buckets){ //处理对象、暂时不用看 } }他{ 場合(GC_ZVAL_GET_COLOR(電流- > U。 PZ)== GC_PURPLE){ TSRMLS_CC u.pz zval_mark_grey(電流- >)。 }他{ GC_ZVAL_SET_ADDRESS(電流- > u.pz、NULL); GC_REMOVE_FROM_BUFFER(現在) } } 電流=電流- >次に、 } }
静的ボイドzval_mark_grey(zvalを* PZ TSRMLS_DC) { バケット* P。 tail_call: IF(GC_ZVAL_GET_COLOR(PZ)= GC_GREY!){ P = NULL; GC_BENCH_INC(zval_marked_grey)。 GC_ZVAL_SET_COLOR(PZ、GC_GREY)。 IF(Z_TYPE_P(PZ)== IS_OBJECT && EG(objects_store).object_buckets){ //对象的处理、暂时不用管 }そうであれば(Z_TYPE_P(PZ)== IS_ARRAY){ IF(Z_ARRVAL_P(PZ)==&EG( symbol_table)){ GC_ZVAL_SET_BLACK(PZ)。 }他{ P = Z_ARRVAL_P(PZ) - > pListHead。 } } 一方(P!= NULL){ PZ = *(zvalを**)のp-> pDataを。 IF(Z_TYPE_P(PZ)= IS_ARRAY || Z_ARRVAL_P(PZ)=&EG(symbol_table)!){ pz-> refcount__gc--。 } IF(P-> pListNext == NULL){ 後藤tail_call。 }他{ zval_mark_grey(PZのTSRMLS_CC)。 } P = P-> pListNext。 } } }
第二の通過gc_root_buffer、ZV色は灰色であり、参照カウント> 0、黒(スパムではない)に設定されているときに参照カウント= 0、その後、白に設定されている場合
静的ボイドgc_scan_roots(TSRMLS_D) { gc_root_buffer *電流= GC_G(根).next。 一方、(!電流=&GC_G(根)){ IF(電流- >ハンドル){ zvalをZ。 INIT_PZVAL(&Z)。 Z_OBJ_HANDLE(Z)=電流- >ハンドル。 Z_OBJ_HT(Z)=電流- > u.handlers。 zobj_scan(&Z TSRMLS_CC)。 }他{ zval_scan(電流- > TSRMLS_CC u.pz)。 } 電流=電流- >次に、 } }
静的INT zval_scan(zvalを* PZのTSRMLS_DC) { バケット* P。 tail_call: IF(GC_ZVAL_GET_COLOR(PZ)== GC_GREY){ P = NULL; IF(pz-> refcount__gc> 0){ zval_scan_black(PZのTSRMLS_CC)。 }他{ GC_ZVAL_SET_COLOR(PZ、GC_WHITE)。 IF(Z_TYPE_P(PZ)== IS_OBJECT && EG(objects_store).object_buckets){ //处理オブジェクト 他}(Z_TYPE_P(PZ)== IS_ARRAY){もし あれば(Z_ARRVAL_P(PZ)==&EG(symbol_table)){ GC_ZVAL_SET_BLACK (PZ)。 }他{ P = Z_ARRVAL_P(PZ) - > pListHead。 } } } ながら(!p = NULL){ IF(P-> pListNext == NULL){ PZ = *(zvalを**)p> pDataを。 後藤tail_call; }他{ zval_scan(*(zvalを**)p> pDataをTSRMLS_CC)。 } P = P-> pListNext。 } } 0を返します。 }
Gc_root_bufferリンクリストトラバーサル、単色ZVリストの配置は白データ、完全に回復されます
静的ボイドgc_collect_roots(TSRMLS_D) { gc_root_buffer *電流= GC_G(根).next。 しばらく(現在!=&GC_G(根)){ 場合(電流- >ハンドル){ 場合(EG(objects_store).object_buckets){ 構造体_store_object * OBJ =&EG(objects_store).object_buckets [電流- >ハンドル] .bucket.obj ; zvalをZ。 GC_SET_ADDRESS(obj->緩衝、NULL); INIT_PZVAL(&Z)。 Z_OBJ_HANDLE(Z)=電流- >ハンドル。 Z_OBJ_HT(Z)=電流- > u.handlers。 zobj_collect_white(&ZのTSRMLS_CC)。 } }他{ GC_ZVAL_SET_ADDRESS(電流- > u.pz、NULL); (TSRMLS_CC u.pzの電流>)zval_collect_white。 } GC_REMOVE_FROM_BUFFER(現在) 現在=の電流>次。 } }
静的ボイドzval_collect_white(zvalを* PZ TSRMLS_DC) { バケット* P。 tail_call: IF(((*)(PZ))zval_gc_info - > u.buffered ==(gc_root_buffer *)GC_WHITE){ P = NULL; GC_ZVAL_SET_BLACK(PZ)。 IF(Z_TYPE_P(PZ)== IS_OBJECT && EG(objects_store).object_buckets){ ... }他{ IF(Z_TYPE_P(PZ)== IS_ARRAY){ P = Z_ARRVAL_P(PZ) - > pListHead。 } } / *参照カウントを復元し、解放するために、リストに入れ* / pz-> refcount__gc ++; ((zval_gc_info *)PZ) - > u.next = GC_G(zval_to_free)。 GC_G(zval_to_free)=(zval_gc_info *)PZ。 (!P = NULL){しばらく PZ = *(zvalを**)のp-> pDataを。 もし(!!Z_TYPE_P(PZ)= IS_ARRAY || Z_ARRVAL_P(PZ)=&EG(symbol_table)){ pz-> refcount__gc ++; } IF(P-> pListNext == NULL){ 後藤tail_call。 }他{ zval_collect_white(PZ TSRMLS_CC)。 } P = P-> pListNext。 } } }