摘要:總結垃圾回收機制以的引用計數機制為基礎以前只有該機制同時使用根緩沖區機制,當發現有存在循環引用的時,就會把其投入到根緩沖區,當根緩沖區達到配置文件中的指定數量后,就會進行垃圾回收,以此解決循環引用導致的內存泄漏問題開始引入該機制
php垃圾回收機制,對于PHPer來說是一個不陌生但是又不是很熟悉的內容。那么php是怎么實現對不需要的內存進行回收的呢?
php變量的內部存儲結構首先還是需要了解下基礎知識,便于垃圾回收原理內容的理解。大家都知道php是由C編寫而成的,所以php變量的內部存儲結構也會和C語言相關,即zval的結構體:
struct _zval_struct { union { long lval; double dval; struct { char *val; int len; } str; HashTable *ht; zend_object_value obj; } value; //變量value值 zend_uint refcount__gc; //引用計數內存中使用次數,為0刪除該變量 zend_uchar type; //變量類型 zend_uchar is_ref__gc; //區分是否是引用變量 };
從上面結構體內容可以看出每一個php變量都會由變量類型、value值、引用計數次數和是否是引用變量四部分組成
注:上面zval結構體是php5.3版本之后的結構,php5.3之前因為沒有引入新的垃圾回收機制,即GC,所以命名也沒有_gc;而php7版本之后由于性能問題所以改寫了zval結構,這里不再表述
引用計數原理了解了php變量的內部存儲結構之后,我們再了解下php變量賦值相關的原理和早期垃圾回收機制
變量容器 非array和object變量每次將常量賦值給一個變量時,都會產生一個變量容器
舉例:
$a = "許錚的技術成長之路"; xdebug_debug_zval("a")
結果:
a: (refcount=1, is_ref=0)="許錚的技術成長之路"array和object變量
會產生元素個數+1的變量容器
舉例:
$b = [ "name" => "許錚的技術成長之路", "number" => 3 ]; xdebug_debug_zval("b")
結果:
b: (refcount=1, is_ref=0)=array ("name" => (refcount=1, is_ref=0)="許錚的技術成長之路", "number" => (refcount=1, is_ref=0)=3)賦值原理(寫時復制技術)
了解了常量賦值之后,接下來我們從內存角度思考變量之間的賦值
舉例:
$a = [ "name" => "許錚的技術成長之路", "number" => 3 ]; //創建一個變量容器,變量a指向給變量容器,a的ref_count為1 $b = $a; //變量b也指向變量a指向的變量容器,a和b的ref_count為2 xdebug_debug_zval("a", "b"); $b["name"] = "許錚的技術成長之路1";//變量b的其中一個元素發生改變,此時會復制出一個新的變量容器,變量b重新指向新的變量容器,a和b的ref_count變成1 xdebug_debug_zval("a", "b");
結果:
a: (refcount=2, is_ref=0)=array ("name" => (refcount=1, is_ref=0)="許錚的技術成長之路", "number" => (refcount=1, is_ref=0)=3) b: (refcount=2, is_ref=0)=array ("name" => (refcount=1, is_ref=0)="許錚的技術成長之路", "number" => (refcount=1, is_ref=0)=3) a: (refcount=1, is_ref=0)=array ("name" => (refcount=1, is_ref=0)="許錚的技術成長之路", "number" => (refcount=1, is_ref=0)=3) b: (refcount=1, is_ref=0)=array ("name" => (refcount=1, is_ref=0)="許錚的技術成長之路1", "number" => (refcount=1, is_ref=0)=3)
所以,當變量a賦值給變量b的時候,并沒有立刻生成一個新的變量容器,而是將變量b指向了變量a指向的變量容器,即內存"共享";而當變量b其中一個元素發生改變時,才會真正發生變量容器復制,這就是寫時復制技術
引用計數清0當變量容器的ref_count計數清0時,表示該變量容器就會被銷毀,實現了內存回收,這也是php5.3版本之前的垃圾回收機制
舉例:
$a = "許錚的技術成長之路"; $b = $a; xdebug_debug_zval("a"); unset($b); xdebug_debug_zval("a");
結果:
a: (refcount=2, is_ref=0)="許錚的技術成長之路" a: (refcount=1, is_ref=0)="許錚的技術成長之路"循環引用引發的內存泄露問題
但是php5.3版本之前的垃圾回收機制存在一個漏洞,即當數組或對象內部子元素引用其父元素,而此時如果發生了刪除其父元素的情況,此變量容器并不會被刪除,因為其子元素還在指向該變量容器,但是由于所有作用域內都沒有指向該變量容器的符號,所以無法被清除,因此會發生內存泄漏,直到該腳本執行結束
舉例:
$a = array( "one" ); $a[] = &$a; xdebug_debug_zval( "a" );
由于該示例不好輸出結果,用圖表示,如圖:
舉例:
unset($a); xdebug_debug_zval("a");
如圖:
php5.3版本之后引入根緩沖機制,即php啟動時默認設置指定zval數量的根緩沖區(默認是10000),當php發現有存在循環引用的zval時,就會把其投入到根緩沖區,當根緩沖區達到配置文件中的指定數量(默認是10000)后,就會進行垃圾回收,以此解決循環引用導致的內存泄漏問題
確認為垃圾的準則1、如果引用計數減少到零,所在變量容器將被清除(free),不屬于垃圾
2、如果一個zval 的引用計數減少后還大于0,那么它會進入垃圾周期。其次,在一個垃圾周期中,通過檢查引用計數是否減1,并且檢查哪些變量容器的引用次數是零,來發現哪部分是垃圾。
垃圾回收機制:
1、以php的引用計數機制為基礎(php5.3以前只有該機制)
2、同時使用根緩沖區機制,當php發現有存在循環引用的zval時,就會把其投入到根緩沖區,當根緩沖區達到配置文件中的指定數量后,就會進行垃圾回收,以此解決循環引用導致的內存泄漏問題(php5.3開始引入該機制)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30911.html
摘要:對于來說,變量有全局變量和局部變量之分那么,他們都是存儲到一個哈希表內了么其實不是的,變量存儲也有作用域的概念。 上次跟大家講了垃圾回收機制后,有些小伙伴對底層原理比較感興趣,私信問我了一些關于變量的相關知識,既然大家對變量比較感興趣,那么這次我們來系統的講一下變量的底層原理 變量結構 首先,我們還是先擺上我們的zval結構體,即php所有變量都會以zval結構體的形式實現 struc...
摘要:什么是線程餓死,什么是活鎖多線程中的忙循環是什么變量是什么變量和變量有什么不同類型變量提供什么保證能使得一個非原子操作變成原子操作嗎 JVM專題 showImg(https://segmentfault.com/img/remote/1460000019943435); (面試題+答案領取方式見個人主頁) Java 類加載過程? 描述一下 JVM 加載 Class 文件的原理機制? ...
摘要:目錄介紹問題匯總具體問題好消息博客筆記大匯總年月到至今,包括基礎及深入知識點,技術博客,學習筆記等等,還包括平時開發中遇到的匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續完善開源的文件是格式的同時也開源了生活博客,從年 目錄介紹 00.Java問題匯總 01.具體問題 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎及深入知識點,Android技...
摘要:它們的用處都是用來能讓數據正常插入到數據庫中,并防止注入,但是并不能做到防止注入。進來抽獎的用戶使用原子加鎖,實現抽獎次數自增,當抽獎次數到達時,返回不中獎。 轉載于:https://zhuanlan.zhihu.com/p/...答案并非標準,是作者經驗之談,僅供參考 mysql_real_escape_string mysql_escape_string有什么本質的區別,有什么用處...
閱讀 1264·2021-11-17 09:33
閱讀 1729·2021-09-09 11:53
閱讀 3179·2021-09-04 16:45
閱讀 1357·2021-08-17 10:12
閱讀 2364·2019-08-30 15:55
閱讀 1770·2019-08-30 15:53
閱讀 2397·2019-08-30 15:52
閱讀 2549·2019-08-29 18:41