搜尋
首頁後端開發php教程PHP之引用計數記憶體管理機制與垃圾回收機制

這篇文章跟大家分享了關於PHP的引用計數記憶體管理機制和垃圾回收機制,有需要帶的朋友可以參考一下

引用賦值

$a = 'apple';
$b = &$a;

上述在程式碼中,我將一個字串賦值給變數a,然後將a的引用賦值給了變數b。顯然,這個時候的記憶體指向應該是這樣的:

$a -> 'apple' <p>a和b指向了同一塊記憶體區域(變數容器<em>zval</em> ),我們透過<code>var_dump($a, $b)</code> 得到<code>string(5) "apple" string(5) "apple"</code> ,這是我們預期的結果。 </p><h2 id="unset函數-與-引用計數">unset函數 與 引用計數</h2><h3 id="unset-函數">unset 函數</h3><p>假如我想將 <code>'apple'</code> 這個字串從記憶體中釋放掉。我是這麼做的:</p><pre class="brush:php;toolbar:false">unset($a);

但是透過再次列印$a $b 兩個變數的訊息,我得到了這樣的結果:Notice: Undefined variable : astring(5) "apple" 。奇怪,$a $b 指向同一個變數容器,又明明將$a釋放了,為什麼$b還是'apple'

其實是這樣的,unset()只是將一個變數符號a(指標)銷毀了,並沒有釋放掉那個變數容器,所以執行完操作後,記憶體指向只是變成了這樣:

'apple' 

引用計數

引用計數(reference count)是每個變數容器中都會存放的一條訊息,它表示目前變數容器正被多少個變數符號所引用。

正如先前的例子,unset()並沒有釋放變數所指向的變數容器,而只是將變數符號銷毀了。同時,將變數容器中的引用計數 減1,當引用計數為0時,也就是說當變數容器不被任何變數引用時,就會觸發php的垃圾回收(錯誤),它便會被釋放(正確)。

修正上述的一個小錯誤: 這個單純的引用計數方式是php 5.2 之前的記憶體管理機制,稱不上是垃圾回收機制,垃圾回收機制是php 5.3 才引進的,垃圾回收機制為的是解決這種單純的引用計數記憶體管理機制的缺陷(即循環引用導致的記憶體洩漏,下文會進行解說)

回到正題,我們用程式碼來驗證一下先前的結論:

$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(0),变量容器的引用计数为1,没有释放
$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a, $b);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(24),变量容器的引用计数为0,得到释放

直接釋放

那要怎麼做才能真正釋放掉'apple' 所佔用的記憶體呢?

利用上述方法,我們可以在unset($a) 之後再unset($b) ,將變數容器的所有引用都銷毀,引用計數減為0了,自然就被釋放掉了。

當然,還有更直接的方法:

$a = null;

直接賦值null 會將$a 所指向的記憶體區域置空,並將引用計數歸零,記憶體便被釋放。

腳本執行結束後的記憶體

對於一般的web程式來說(fpm模式下),php的執行是單執行緒同步阻塞型的,當腳本執行結束後,腳本內使用的所有記憶體都會被釋放。那麼,我們手動去釋放記憶體到底有意義嗎?

其實關於這個問題,早有解答,推薦大家看一下鳥哥@laruence 2012年發表的一篇文章:

請手動釋放你的資源(Please release resources manually)

引用計數記憶體管理機制的缺陷:循環引用

現在我們來講講之前提到的引用計數記憶體管理機制的缺陷。

當一個變數容器的引用數為0時,php會進行垃圾回收。但是,你可想過,有一種情況會導致一個變數容器的引用計數永遠不會被減為0,舉個例子:

$a = ['one'];
$a[] = &$a;

我們看到,$a數組第二個元素就是它本身。那麼,存放數組的這個變數容器的引用計數為2,一個引用是變數a,另一個引用是這個陣列的第二個元素 - 索引1

PHP之引用計數記憶體管理機制與垃圾回收機制

那麼,如果這時我們unset($a) ,存放數組的變數容器的引用計數會減1 ,但還有1個引用,就是數組的元素1 ,現在引用結構變成了這樣:

PHP之引用計數記憶體管理機制與垃圾回收機制

由於變數容器的引用計數沒有變成0,所以不能被釋放,而且這時又沒有外部其他變數符號引用它,使用者也沒有辦法去清除這個結構,這時它就會一直駐留在記憶體之中。

所以如果程式碼中存在大量的這種結構和操作,最終會導致記憶體損耗甚至洩漏。這就是 循環引用 帶來的記憶體無法釋放的問題。

慶幸的是,fpm模式下,當請求的腳本執行結束,php會釋放所有腳本中使用到的內存,包括這個結構。但是,如果是守護程式下的php程式呢?比如swoole。 這個php需要解決的急迫問題(已經解決,見下文)。

PHP 5.3.0 引入的同步演算法

傳統上,像以前的 php 用到的引用計數記憶體機制,無法處理循環引用的記憶體洩漏。然而 5.3.0 PHP 使用文章 » 引用計數系統中的同步週期回收(Concurrent Cycle Collection in Reference Counted Systems) 中的同步演算法,解決了這個記憶體洩漏問題,這個演算法就是PHP的垃圾回收機制。

具體演算法的實現和流程有些許複雜,請閱讀官方文檔,這裡不再贅述,另附上幾個演算法流程講解的文章鏈接,講得比較直白:

http://php.net/manual/zh/feat...官方文件
http://www.cnblogs.com/leoo2s...
https://blog.csdn.net/phpkern. ..

最後,還是引用鳥哥文章的這兩段來說明問題:

在PHP5.2以前, PHP使用引用計數(Reference count)來做資源管理, 當一個zval的引用計數為0的時候, 它就會被釋放. 雖然存在循環引用(Cycle reference), 但這樣的設計對於開發Web腳本來說, 沒什麼問題, 因為Web腳本的特點和它追求的目標就是執行時間短, 不會長期運行. 對於循環引用造成的資源洩露, 會在請求結束時釋放掉. 也就是說, 請求結束時釋放資源, 是一種補救措施(backup).

然而, 隨著PHP被越來越多的人使用, 就有很多人在一些後台腳本使用PHP, 這些腳本的特點是長期運行, 如果存在循環引用, 導致引用計數無法及時釋放不用的資源, 則這個腳本最終會內存耗盡退出.

所以在PHP5.3以後, 我們引入了GC, 也就是說, 我們引入GC是為了解決用戶無法解決的問題.


以上是PHP之引用計數記憶體管理機制與垃圾回收機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何防止會話固定攻擊?如何防止會話固定攻擊?Apr 28, 2025 am 12:25 AM

防止會話固定攻擊的有效方法包括:1.在用戶登錄後重新生成會話ID;2.使用安全的會話ID生成算法;3.實施會話超時機制;4.使用HTTPS加密會話數據,這些措施能確保應用在面對會話固定攻擊時堅不可摧。

您如何實施無會話身份驗證?您如何實施無會話身份驗證?Apr 28, 2025 am 12:24 AM

實現無會話身份驗證可以通過使用JSONWebTokens(JWT)來實現,這是一種基於令牌的認證系統,所有的必要信息都存儲在令牌中,無需服務器端會話存儲。 1)使用JWT生成和驗證令牌,2)確保使用HTTPS防止令牌被截獲,3)在客戶端安全存儲令牌,4)在服務器端驗證令牌以防篡改,5)實現令牌撤銷機制,如使用短期訪問令牌和長期刷新令牌。

PHP會議有哪些常見的安全風險?PHP會議有哪些常見的安全風險?Apr 28, 2025 am 12:24 AM

PHP會話的安全風險主要包括會話劫持、會話固定、會話預測和會話中毒。 1.會話劫持可以通過使用HTTPS和保護cookie來防範。 2.會話固定可以通過在用戶登錄前重新生成會話ID來避免。 3.會話預測需要確保會話ID的隨機性和不可預測性。 4.會話中毒可以通過對會話數據進行驗證和過濾來預防。

您如何銷毀PHP會議?您如何銷毀PHP會議?Apr 28, 2025 am 12:16 AM

銷毀PHP會話需要先啟動會話,然後清除數據並銷毀會話文件。 1.使用session_start()啟動會話。 2.用session_unset()清除會話數據。 3.最後用session_destroy()銷毀會話文件,確保數據安全和資源釋放。

如何更改PHP中的默認會話保存路徑?如何更改PHP中的默認會話保存路徑?Apr 28, 2025 am 12:12 AM

如何改變PHP的默認會話保存路徑?可以通過以下步驟實現:在PHP腳本中使用session_save_path('/var/www/sessions');session_start();設置會話保存路徑。在php.ini文件中設置session.save_path="/var/www/sessions"來全局改變會話保存路徑。使用Memcached或Redis存儲會話數據,如ini_set('session.save_handler','memcached');ini_set(

您如何修改PHP會話中存儲的數據?您如何修改PHP會話中存儲的數據?Apr 27, 2025 am 12:23 AM

tomodifyDataNaphPsession,startTheSessionWithSession_start(),然後使用$ _sessionToset,修改,orremovevariables.1)startThesession.2)setthesession.2)使用$ _session.3)setormodifysessessvariables.3)emovervariableswithunset()

舉一個在PHP會話中存儲數組的示例。舉一個在PHP會話中存儲數組的示例。Apr 27, 2025 am 12:20 AM

在PHP會話中可以存儲數組。 1.啟動會話,使用session_start()。 2.創建數組並存儲在$_SESSION中。 3.通過$_SESSION檢索數組。 4.優化會話數據以提升性能。

垃圾收集如何用於PHP會議?垃圾收集如何用於PHP會議?Apr 27, 2025 am 12:19 AM

PHP會話垃圾回收通過概率機制觸發,清理過期會話數據。 1)配置文件中設置觸發概率和會話生命週期;2)可使用cron任務優化高負載應用;3)需平衡垃圾回收頻率與性能,避免數據丟失。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器