亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

淺談PHP源碼三十四:PHP5.3新增加的垃圾回收機制

2020-03-22 19:29:55
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了關于淺談PHP源碼三十四:PHP5.3新增加的垃圾回收機制(Garbage Collection),有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

淺談PHP源碼三十四:PHP5.3新增加的垃圾回收機制(Garbage Collection)
在之前的文章淺談PHP源碼三十三:PHP5.3新增加的垃圾回收機制(Garbage Collection)基礎 中有介紹了垃圾回收機制的一些基礎知識。今天我們看看其初始化,添加到垃圾緩沖區和垃圾回收的過程。
官方說明文檔請猛擊Garbage Collection
中文版地址:http://docs.php.net/manual/zh/features.gc.php
【初始化】
在zend/zend_gc.c 121行有函數gc_init實現了gc的初始化,其代碼如下:

 ZEND_API void 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);}}

第123行判斷是否為空和是否開啟了gc,如果都為真,則轉124行
第124行是直接調用malloc分配了10000個gc_root_buffer內存。
第125行將html' target='_blank'>全局變量last_unused設置為gc緩沖區的結束位置。
第126行重置整個垃圾收集機制,其代碼從zend/zend_gc.c 88行開始,如下:

ZEND_API void gc_reset(TSRMLS_D){GC_G(gc_runs) = 0;GC_G(collected) = 0; #if GC_BENCHGC_G(root_buf_length) = 0;GC_G(root_buf_peak) = 0;GC_G(zval_possible_root) = 0;GC_G(zobj_possible_root) = 0;GC_G(zval_buffered) = 0;GC_G(zobj_buffered) = 0;GC_G(zval_remove_from_buffer) = 0;GC_G(zobj_remove_from_buffer) = 0;GC_G(zval_marked_grey) = 0;GC_G(zobj_marked_grey) = 0;#endif GC_G(roots).next = GC_G(roots);GC_G(roots).prev = GC_G(roots); if (GC_G(buf)) {GC_G(unused) = NULL;GC_G(first_unused) = GC_G(buf); GC_G(zval_to_free) = NULL;} else {GC_G(unused) = NULL;GC_G(first_unused) = NULL;GC_G(last_unused) = NULL;}}

第90~91行 設置gc運行的次數統計(gc_runs)和gc中垃圾的個數(collected)為0。
第106~107行 設置雙向鏈表頭結點的上一個結點和下一個結點指向自己。

關于gc_enabled,默認情況下是開啟的,可以在php.ini中配置。
其實現代碼在zend/zend.c 93行 如下:

STD_ZEND_INI_BOOLEAN( zend.enable_gc , 1 ,ZEND_INI_ALL,OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals)

初始化調用在zend/zend.c 79 行

 static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */{OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); if (GC_G(gc_enabled)) {gc_init(TSRMLS_C);} return SUCCESS;}

【添加到垃圾緩沖區】
跟蹤PHP的源碼 zend/zend_execute_API.c 424行
[_zval_ptr_dtor] - [GC_ZVAL_CHECK_POSSIBLE_ROOT()] - [gc_zval_check_possible_root()] - [gc_zval_possible_root()]
其中在gc_zval_check_possible_root()函數中,僅對數組和對象執行垃圾回收操作

gc_zval_possible_root函數的代碼如下:

ZEND_API void 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))) {/* The given zval is a garbage that is going to be deleted by * currently running GC */return;} if (zv- type == IS_OBJECT) {GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);return;GC_BENCH_INC(zval_possible_root); if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {GC_ZVAL_SET_PURPLE(zv); if (!GC_ZVAL_ADDRESS(zv)) {gc_root_buffer *newRoot = GC_G(unused); if (newRoot) {GC_G(unused) = newRoot- prev;} else if (GC_G(first_unused) != GC_G(last_unused)) {newRoot = GC_G(first_unused);GC_G(first_unused)++;} else {if (!GC_G(gc_enabled)) {GC_ZVAL_SET_BLACK(zv);return;zv- refcount__gc++;gc_collect_cycles(TSRMLS_C);zv- refcount__gc--;newRoot = GC_G(unused);if (!newRoot) {return;GC_ZVAL_SET_PURPLE(zv);GC_G(unused) = newRoot- prev;newRoot- next = GC_G(roots).next;newRoot- prev = GC_G(roots);GC_G(roots).next- prev = newRoot;GC_G(roots).next = newRoot; GC_ZVAL_SET_ADDRESS(zv, newRoot); newRoot- handle = 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);}}

第132~140行 檢查zval結點信息是否已經放入到結點緩沖區,如果已經放入到結點緩沖區,則直接返回,這樣可以優化其性能

第142~145行 處理對象結點,直接返回,不再執行后面的操作

第149行 判斷結點是否已經被標記為紫色,如果為紫色則不再添加到結點緩沖區,此處在于保證一個結點只執行一次添加到緩沖區的操作。

第150行 將結點的顏色標記為紫色,表示此結點已經添加到緩沖區,下次不用再做添加

第153~157行 找出新的結點的位置,如果緩沖區滿了,則執行垃圾回收操作。

第176~184行 將新的結點添加到緩沖區所在的雙向鏈表。

【垃圾回收過程】
在gc_zval_possible_root函數中,當緩沖區滿時,程序調用gc_collect_cycles函數,執行垃圾回收操作。從zend/zend_gc.c文件615行開始,其實現代碼如下:

 ZEND_API int gc_collect_cycles(TSRMLS_D){int count = 0; if (GC_G(roots).next != GC_G(roots)) {zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free; if (GC_G(gc_active)) {return 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; /* First call destructors */while (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)].valid 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)].destructor_called = 1;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--;count++;p = p- u.next;} /* Destroy zvals */p = GC_G(free_list);while (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)].valid 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.refcount = 1;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);} else if (Z_TYPE(p- z) == IS_ARRAY) {Z_TYPE(p- z) = IS_NULL;zend_hash_destroy(Z_ARRVAL(p- FREE_HASHTABLE(Z_ARRVAL(p- } else {zval_dtor( p- Z_TYPE(p- z) = IS_NULL;p = GC_G(next_to_free);} /* Free zvals */p = GC_G(free_list);while (p != FREE_LIST_END) {q = p- u.next;FREE_ZVAL_EX( p- p = q;GC_G(collected) += count;GC_G(free_list) = orig_free_list;GC_G(next_to_free) = orig_next_to_free;} return count;}

第619行 判斷緩沖區是否為空,如果為空則不會執行垃圾回收操作
第622行 判斷垃圾回收操作是否正則進行,如果正在進行,則直接返回
第625~627行 將垃圾回收操作次數加1,初始化空閑列表,設置gc_active為1表示垃圾回歸正在進行
第628行 此處為其官方文檔中算法的步驟 B ,算法使用深度優先搜索查找所有可能的根,找到后將每個變量容器中的引用計數減1″,為確保不會對同一個變量容器減兩次”1″,用灰色標記已減過1的。
第629行 這是算法的步驟 C ,算法再一次對每個根節點使用深度優先搜索,檢查每個變量容器的引用計數。如果引用計數是 0 ,變量容器用白色來標記。如果引用次數大于0,則恢復在這個點上使用深度優先搜索而將引用計數減1的操作(即引用計數加1),然后將它們重新用黑色標記。
第630行 算法的最后一步 D ,算法遍歷根緩沖區以從那里刪除變量容器根(zval roots),同時,檢查是否有在上一步中被白色標記的變量容器。每個被白色標記的變量容器都被清除。
在[gc_collect_cycles() - gc_collect_roots() - zval_collect_white() ]中我們可以看到,對于白色標記的結點會被添加到全局變量zval_to_free列表中。此列表在后面的操作中有用到。
第632~633行 將全局變量free_list和next_to_free存放在相對應當的臨時變量中,在最后會恢復到此時的狀態。
第634~635行 初始化需要清除的列表,清空將要清空的zval列表并且將垃圾收集的操作狀態為不激活狀態。
第639~655行 第一次調用析構函數,并統計清除的變量個數
第657~678行 清除變量
第682~686行 釋放內存
第687~689行 處理垃圾個數統計,恢復free_list和next_to_free變量

以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP !

相關推薦:

淺談PHP源碼三十三:PHP5.3新增加的垃圾回收機制(Garbage Collection)基礎

淺談PHP源碼三十二:PHP內存池中的emalloc/efree層與堆(heap)層

淺談PHP源碼二十九:關于接口的繼承

以上就是淺談PHP源碼三十四:PHP5.3新增加的垃圾回收機制(Garbage Collection)的詳細內容,PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美精品在线观看| 操人视频在线观看欧美| 精品久久久久久久久久久久| 91人人爽人人爽人人精88v| 国产精品一区二区三区成人| 日韩福利伦理影院免费| 国内精品400部情侣激情| 欧美日韩一区二区三区在线免费观看| 久久69精品久久久久久国产越南| 亚洲精品美女久久| 国产综合久久久久| 久久久91精品国产| 91在线免费观看网站| 国产亚洲一级高清| 北条麻妃一区二区在线观看| 国产精品亚洲精品| 久久免费少妇高潮久久精品99| 欧美日韩一区二区在线播放| 久久久免费观看视频| 中文字幕精品在线视频| 欧美日韩激情小视频| 欧美www在线| 欧美日韩国产成人| 91精品国产自产在线| 久久国产精品影视| 亚洲女人天堂成人av在线| 色偷偷噜噜噜亚洲男人| 亚洲精品久久久久中文字幕欢迎你| 欧美丰满少妇xxxx| 欧美精品激情在线| 国产日韩欧美另类| 亚洲天堂av综合网| 91精品免费久久久久久久久| 国产亚洲欧洲高清一区| 日韩国产高清视频在线| 欧美视频在线视频| 欧美国产第二页| 一区二区三区久久精品| 精品少妇v888av| 57pao成人国产永久免费| 亚洲精品白浆高清久久久久久| www.日韩视频| 国产精品96久久久久久| 亚洲欧美在线免费观看| 欧美精品手机在线| 亚洲一区中文字幕| 欧美激情一区二区三区在线视频观看| 久久免费国产视频| 亚洲免费av电影| 欧美裸体xxxx极品少妇软件| 欧美日韩成人网| 国产亚洲精品激情久久| 中文字幕日韩免费视频| 欧美亚洲另类在线| 国产精品精品国产| 日韩精品在线观看一区| 成人av番号网| 欧美日韩中文在线| 色噜噜狠狠色综合网图区| 亚洲护士老师的毛茸茸最新章节| 亚洲桃花岛网站| 欧美精品免费在线观看| 国产一区二区三区在线视频| 亚洲欧美综合v| www.午夜精品| 日韩在线视频二区| 欧美精品videos另类日本| 91精品国产91久久久久久吃药| 国产日产欧美精品| 国产日本欧美一区| 欧美裸体xxxx极品少妇软件| 麻豆乱码国产一区二区三区| 97在线视频国产| 国产精品旅馆在线| 国产91在线播放精品91| 中文字幕日韩欧美在线视频| 久久久亚洲国产天美传媒修理工| 亚洲视频在线播放| 国产原创欧美精品| 国产精品久久久久久久久男| 日本精品视频在线观看| 亚洲福利视频网站| 97香蕉超级碰碰久久免费的优势| 久久久久久久久网站| 亚洲综合精品伊人久久| 狠狠操狠狠色综合网| 最近2019免费中文字幕视频三| 大荫蒂欧美视频另类xxxx| 久久777国产线看观看精品| 91精品视频在线播放| 精品国产一区二区在线| 欧美成人免费一级人片100| 97超级碰在线看视频免费在线看| 亚洲欧美日韩国产成人| 欧美激情在线狂野欧美精品| 91在线观看免费网站| 揄拍成人国产精品视频| 日韩a**站在线观看| 日韩一级黄色av| 欧美在线精品免播放器视频| 97av在线视频免费播放| 日韩av网站在线| 91精品国产91久久久久| 国产亚洲精品久久久久久| 久久久亚洲影院你懂的| 欧美日韩国产一区二区| 中文字幕日韩精品在线观看| 国产精品夫妻激情| 中文国产亚洲喷潮| 欧美日韩爱爱视频| 久久av在线看| 久久久久久国产三级电影| 日韩电影免费观看在线观看| 中文字幕亚洲综合| 久久久久久久久电影| 欧美日韩国产123| 日本精品久久久久影院| 久久影院资源站| 精品亚洲一区二区三区在线观看| 免费av一区二区| 国产精自产拍久久久久久| 中文字幕亚洲一区二区三区五十路| 成人女保姆的销魂服务| 精品国产1区2区| 国产精品在线看| 欧美日韩国内自拍| 色综合五月天导航| 成人久久18免费网站图片| 亚洲国产欧美日韩精品| 欧美极品第一页| 亚洲精品有码在线| 国产精品美女av| 国产成人aa精品一区在线播放| 久青草国产97香蕉在线视频| 一本一本久久a久久精品牛牛影视| 亚洲高清久久网| 国产午夜精品麻豆| 91理论片午午论夜理片久久| 欧美午夜www高清视频| 亚洲自拍偷拍区| 欧美精品在线免费观看| 中文字幕欧美亚洲| 国产精品www网站| 亚洲欧洲一区二区三区久久| 国产亚洲免费的视频看| 亚洲精品国产suv| 国模私拍一区二区三区| 久久久之久亚州精品露出| 7777免费精品视频| 精品视频在线播放| 亚洲国产精品久久精品怡红院| 日韩电影中文 亚洲精品乱码| 久久精品91久久久久久再现| 欧美精品videossex性护士| 色婷婷av一区二区三区久久| 久久久久久久久久久av| 中文字幕一精品亚洲无线一区| 精品久久久久久久久久久| 色综合色综合网色综合| 日韩精品在线观| 91美女片黄在线观| 日本久久久a级免费| 国产精国产精品| 亚洲一区中文字幕在线观看|