PHP下文中不再使用的變數是否會被立即回收?

來源:互聯網
上載者:User
$huge_var = "Long long string variable.....";//使用與不使用這一句$huge_var = null;//以下有非常多的代碼,但跟$huge_var無關//非常多的代碼//代碼快要結束,此時此刻,$huge_var佔用的記憶體回收了嗎?解譯器在預先處理的時候有無此類最佳化操作?//前面$huge_var = null的使用與否對此時此刻整個PHP指令碼的記憶體佔用量有無影響?

回複內容:

$huge_var = "Long long string variable.....";//使用與不使用這一句$huge_var = null;//以下有非常多的代碼,但跟$huge_var無關//非常多的代碼//代碼快要結束,此時此刻,$huge_var佔用的記憶體回收了嗎?解譯器在預先處理的時候有無此類最佳化操作?//前面$huge_var = null的使用與否對此時此刻整個PHP指令碼的記憶體佔用量有無影響?

如果你的這個變數是一個全域變數$GLOBALS['huge_var'],如果你不手動用unset($huge_var)釋放,那麼只有等到指令碼運行結束後才會被回收.不過就算你沒有釋放,運行在PHP-FPM或MOD_PHP的時候問題也不大,因為PHP-FPM在請求結束後會釋放掉所有資源,所以不會產生記憶體泄露.但如果你編寫的是CLI命令列指令碼,尤其是Daemon守護進程(while(true){})的PHP指令碼時,就應該注意使用unset釋放掉不再使用的變數了,避免記憶體泄露.

可見unset是能夠釋放PHP進程佔用的系統記憶體的,特別是在釋放大數組或者長字串的時候尤其明顯.

函數中的局部變數是不需要手動釋放的,函數執行完成後會自動釋放.函數中可以用$GLOBALS['huge_var']或者global $huge_var訪問到你的全域變數.

memory_get_usage 返回分配給PHP指令碼的記憶體,單位是位元組,不包括PHP進程的記憶體.
memory_get_peak_usage 返回分配給PHP指令碼的記憶體的峰值.

PHP5記憶體回收機制:
http://php.net/manual/zh/features.gc.php
每個PHP變數存在一個叫"zval"的變數容器中。

$a = 'new string'; //當一個變數被賦常量值時,就會產生一個zval變數容器xdebug_debug_zval('a'); //輸出 a: (refcount=1, is_ref=0)=string(10) "new string";$b = $a;xdebug_debug_zval('a'); //輸出 a: (refcount=2, is_ref=0)=string(10) "new string"unset($b);xdebug_debug_zval('a'); //輸出 a: (refcount=1, is_ref=0)=string(10) "new string"

可見產生了類型為string和值為new string的變數容器a.
在額外的兩個位元組資訊中,is_ref被預設設定為FALSE,因為沒有任何自訂的引用產生.
refcount被設定為1,因為這裡只有一個變數使用這個變數容器.
如果我們現在執行unset($a),包含類型和值的這個變數容器就會從記憶體中刪除.

如果一個引用計數增加,它將繼續被使用,當然就不再在垃圾中.
如果引用計數減少到零,所在變數容器將被清除(free).
就是說,僅僅在引用計數減少到非零值時,才會產生垃圾周期(garbage cycle).
其次,在一個垃圾周期中,通過檢查引用計數是否減1,並且檢查哪些變數容器的引用次數是零,來發現哪部分是垃圾.
php.ini中預設啟用循環參考收集器:
zend.enable_gc = On
PHP可以用gc_enabled判斷是否迴圈,可以用gc_enable/gc_disable顯式啟用或禁用循環參考收集器.
即使在可能根緩衝區還沒滿時,也能調用gc_collect_cycles強制執行循環回收.
允許開啟和關閉記憶體回收機制並且允許自主的初始化的原因,是由於你的應用程式的某部分可能是高時效性的.
在這種情況下,你可能不想使用記憶體回收機制.
當然,對你的應用程式的某部分關閉記憶體回收機制,是在冒著可能記憶體流失的風險,因為一些可能根也許存不進有限的根緩衝區.
因此,就在你調用gc_disable()函數釋放記憶體之前,先調用gc_collect_cycles()函數可能比較明智.
因為這將清除已存放在根緩衝區中的所有可能根,然後在記憶體回收機制被關閉時,可留下空緩衝區以有更多空間儲存可能根.

if(gc_enabled()) { gc_collect_cycles(); gc_disable();}

PHP記憶體泄露指的是你保持了對變數的引入導致GC無法收集.

PHP記憶體回收對效能的影響:
第一個是節省了記憶體佔用空間,另一個是記憶體回收機制執行記憶體清理時的執行時間增加.

為什麼禁用記憶體回收(GC)會給composer帶來巨大的運行效率提升?
由於PHP的記憶體回收是基於引用計數的,為了能夠回收循環參考的對象,會在引用計數減少但不到0的時候,試圖檢測並回收循環參考的孤島對象,但當有效對象的數量及互相引用較大(比如composer中代表包、版本和互相的依賴關係)的時候,這種搜尋的開銷就會變得非常巨大,造成大量的CPU計算。composer在啟動並執行時候會在記憶體建立大量的對象,這些對象會觸發GC機制,而這些對象需要被使用,所以GC無法清除。因此,使用gc_disable禁用GC之後,能節省CPU時間,效率更高。

很少在意這些 因為指令碼執行完了什麼都沒了 除非是一些持久化的串連
就算釋放也只是現在和一會兒的區別 又不是像java一個容器跑起來沒完沒了

經過實驗,答案是不會立即回收。

還是加上$var = null來回收記憶體吧,或者寫成匿名變數,或者利用函數範圍。

//代碼快要結束了,此時此刻,$huge_var佔用的記憶體回收了嗎?

明顯沒有啊,這個地方你還可以繼續用$huge_var這個變數,不是嗎?

$huge_var = null;

上面這句會把記憶體釋放掉,如果真的是有“非常多的代碼”,最好用上這句。

另外,如果$huge_var真的很大,你就該思考下,$huge_var真的是有必要的嗎?
可以考慮使用PHP的“流”相關的函數。

在php中,一個進程開始執行,引擎會先申請一塊記憶體,在運行中不夠在再這個基礎上申請。
中間如果有變數被unset或賦值null,它所佔的記憶體會被回收,但是不會還給系統記憶體,依舊被引擎保留著,只有當這個進程結束,php所佔的記憶體才會被釋放掉。
因此在操作容易爆記憶體超出的時候,可以把這個進程分多個進程進行處理。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.