目錄
PHP的垃圾回收机制详解
首頁 後端開發 php教程 PHP的垃圾回收机制详解_PHP教程

PHP的垃圾回收机制详解_PHP教程

Jul 13, 2016 am 10:10 AM
垃圾 機制

PHP的垃圾回收机制详解

最近由于使用php编写了一个脚本,模拟实现了一个守护进程,因此需要深入理解php中的垃圾回收机制。本文参考了PHP手册。
 
在理解PHP垃圾回收机制(GC)之前,先了解一下变量的存储。
 
php中变量存在于一个zval的变量容器中。结构如下:
 
 
 
 
 
类型
 
 
is_ref
 
refcount
 
 
 
 
 
zval中,除了存储变量的类型和值之外,还有is_ref字段和refcount字段。
 
is_ref:是个bool值,用来区分变量是否属于引用集合。什么意思呢,你可以这么认为:表示变量是否有一个以上的别名。 
refcount:计数器,表示指向这个zval变量容器的变量个数。 
两者之间有这么一个默认关系:当refcount值为1时,is_ref的值为false。因为refcount为1,此变量不可能有多个别名,也就不存在引用了。
 
安装xdebug拓展之后,可以利用xdebug_debug_zval打印出zval容器详情。
 
这里有一点需要注意,将一个变量 = 赋值给另一个变量时,不会立即为新变量分配内存空间,而是在原变量的zval中给refcount加1。 只有当原变量或者发生改变时,才会为新变量分配内存空间,同时原变量的refcount减 1 。当然,如果unset原变量,新变量直接就使用原变量的zval而不是重新分配。
 
 &引用赋值时,原变量的is_ref 变为1,refcount 加1.  如果给一个变量&赋值,之前 = 赋值的变量会分配空间。
 
 
 
 
$a = 1;
xdebug_debug_zval('a');
echo PHP_EOL;
$b = $a;
xdebug_debug_zval('a');
echo PHP_EOL;
 
$c = &$a;
xdebug_debug_zval('a');
echo PHP_EOL;
 
xdebug_debug_zval('b');
echo PHP_EOL;
?>
  运行结果如下:
 
a:(refcount=1, is_ref=0),int 1
 
a:(refcount=2, is_ref=0),int 1
 
a:(refcount=2, is_ref=1),int 1
 
b:(refcount=1, is_ref=0),int 1
 
 
 
 
 
上面描述的zval存储的是标量,那复合类型的数组是如何存储的呢?
 
 
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
echo PHP_EOL;
class Test{
    public $a = 1;
    public $b = 2;
     
    function handle(){
        echo 'hehe';
    }
}
 
$test = new Test();
xdebug_debug_zval('test');
?>
  运行结果如下:
 
a:(refcount=1, is_ref=0),
 
array
  'meaning' => (refcount=1, is_ref=0),
string
 
'life' (length=4)
  'number' => (refcount=1, is_ref=0),
int
 
 42
test:(refcount=1, is_ref=0),
 
object(Test)[1]
  public 'a' => (refcount=2, is_ref=0),
int
 
 1
  public 'b' => (refcount=2, is_ref=0),
int
 
2
 
可以看出,数组用了比数组长度多1个zval存储。对象类似。下面给出了数组的存储形象表示
 
 
 
可以看到:数组分配了三个zval容器:a   meaning  number
 
现在看看所谓的环状引用是如何生成的
 
 
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
?>
  运行结果:
 
a:(refcount=2, is_ref=1),
 
array
  0 => (refcount=1, is_ref=0),
string
 
 'one' (length=3)
  1 => (refcount=2, is_ref=1), &array
 
a 和 1 的zval容器 是一样的。如下:
 
 
 
 
 
 
 
这样就形成了环状引用。
 
在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,如果refcount为0,那么变量的空间可以被释放,否则就不释放,这是一种非常简单的GC实现。
 
现在unset ($a),那么array的refcount减1变为1.现在无任何变量指向这个zval,而且这个zval的计数器为1,不会回收。
 
 
 
 
 
尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素“1”仍然指向数组本身,所以这个容器不能被清除 。因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。庆幸的是,php将在请求结束时清除这个数据结构,但是在php清除之前,将耗费不少空间的内存。如果你要实现分析算法,或者要做其他像一个子元素指向它的父元素这样的事情,这种情况就会经常发生。当然,同样的情况也会发生在对象上,实际上对象更有可能出现这种情况,因为对象总是隐式的被引用。
 
 
 
如果上面的情况发生仅仅一两次倒没什么,但是如果出现几千次,甚至几十万次的内存泄漏,这显然是个大问题。在长时间运行的脚本,比如请求基本上不会结束的守护进程时,就会出现问题,内存空间会不断耗费,导致内存不足而崩溃。
 
 
 
PHP5.3中,采用了专门的算法(比较复杂)。,来处理环状引用导致内存泄露的问题。
 
当一个zval可能为垃圾时,回收算法会把这个zval放入一个内存缓冲区。当缓冲区达到最大临界值时(最大值可以设置),回收算法会循环遍历所有缓冲区中的zval,判断其是否为垃圾,并进行释放处理。或者我们在脚本中使用gc_collect_cycles,强制回收缓冲区中的垃圾。
 
在php5.3的GC中,针对的垃圾做了如下说明:
 
1:如果一个zval的refcount增加,那么此zval还在使用,肯定不是垃圾,不会进入缓冲区
 
2:如果一个zval的refcount减少到0, 那么zval会被立即释放掉,不属于GC要处理的垃圾对象,不会进入缓冲区。
 
 3:如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾,将其放入缓冲区。PHP5.3中的GC针对的就是这种zval进行的处理。
 
 
 
 
 
开启/关闭垃圾回收机制可以通过修改php配置实现,也可以在程序中使用gc_enable() 和 gc_disable()开启和关闭。
 
 
 
开启垃圾回收机制后,针对内存泄露的情况,可以节省大量的内存空间,但是由于垃圾回收算法运行耗费时间,开启垃圾回收算法会增加脚本的执行时间。
 
下面是php手册中给的一个脚本
 
 
class Foo
{
    public $var = '3.1415962654';
}
 
$baseMemory = memory_get_usage();
 
for ( $i = 0; $i
{
    $a = new Foo;
    $a->self = $a;
    if ( $i % 500 === 0 )
    {
        echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "\n";
    }
}
?>
  
 
针对这个脚本,给出了其在php5.2和5.3中内存的占用情况,如下图:
 
 
 
针对下面这个脚本
 
 
class Foo
{
    public $var = '3.1415962654';
}
 
for ( $i = 0; $i
{
    $a = new Foo;
    $a->self = $a;
}
 
echo memory_get_peak_usage(), "\n";
?>
  
 
开启垃圾回收机制,相对于不开启的时候,脚本执行时间增加了7%
 
通常,PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中应根本就没有性能影响。
 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/938943.htmlTechArticlePHP的垃圾回收机制详解 最近由于使用php编写了一个脚本,模拟实现了一个守护进程,因此需要深入理解php中的垃圾回收机制。本文参考了...
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱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

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
深入了解CSS佈局重新計算與渲染的機制 深入了解CSS佈局重新計算與渲染的機制 Jan 26, 2024 am 09:11 AM

CSS回流(reflow)和重繪(repaint)是網頁效能優化中非常重要的概念。在開發網頁時,了解這兩個概念的工作原理,可以幫助我們提高網頁的回應速度和使用者體驗。本文將深入探討CSS回流和重繪的機制,並提供具體的程式碼範例。一、CSS回流(reflow)是什麼?當DOM結構中的元素發生視覺性、尺寸或位置改變時,瀏覽器需要重新計算並套用CSS樣式,然後重新佈局

PHP中的自動載入機制 PHP中的自動載入機制 Jun 18, 2023 pm 01:11 PM

隨著PHP語言越來越受歡迎,開發人員需要使用越來越多的類別和函數。當專案規模擴大時,手動引入所有依賴項將變得不切實際。這時候就需要一種自動載入機制來簡化程式碼開發和維護過程。自動載入機制是一種PHP語言的特性,可以在運行時自動載入所需的類別和接口,並減少手動的類別文件引入。這樣,程式設計師可以專注於開發程式碼,減少因繁瑣的手動類別引入而產生的錯誤和時間浪費。在PHP中,一般

win10清理系統垃圾的步驟教學 win10清理系統垃圾的步驟教學 Jul 13, 2023 pm 09:53 PM

有些使用者在使用電腦的時候,出現了win10系統清理垃圾的情況,當遇到win10系統清理垃圾這種情況,我們該如何解決呢?如今還有很多用戶不知道如何處理win10系統清理垃圾的情況,那麼接下來就來看看win10清理系統垃圾的步驟教程,大家一起來看看吧。 1、在電腦桌面上,點選“此電腦”,管理。 2、選擇磁碟管理3、選擇你要清理的磁碟,並右鍵選擇屬性。 4、點擊頁面下方的“磁碟清理”按鈕5、在出現的介面中,選擇要清理的文件,點擊“確定”,點擊“刪除文件”即可。以上就是win10清理系統垃圾的步驟教學啦,希望

Go語言垃圾回收機制詳解 Go語言垃圾回收機制詳解 Mar 26, 2024 pm 02:42 PM

Go語言(也稱為Golang)是Google開發的一種高效的程式語言,具有並發性和垃圾回收機制等特點。本文將詳細解釋Go語言中的垃圾回收機制,包括其原理、實作方式以及程式碼範例。 1.垃圾回收原理Go語言的垃圾回收機制是透過「標記-清除」演算法實現的。在程式運行過程中,Go運行時會在堆中追蹤哪些物件是可以被存取的(被標記),而哪些物件是無法被存取的,也就是垃圾資料(需要清除

深入探討Golang變數的儲存位置與機制 深入探討Golang變數的儲存位置與機制 Feb 28, 2024 pm 09:45 PM

標題:深入探討Golang變數的儲存位置和機制隨著Go語言(Golang)在雲端運算、大數據和人工智慧領域的應用逐漸增多,深入了解Golang變數的儲存位置和機制變得尤為重要。在本文中,我們將詳細探討Golang中變數的記憶體分配、儲存位置以及相關的機制。透過具體程式碼範例,幫助讀者更好地理解Golang變數在記憶體中是如何儲存和管理的。 1.Golang變數的內存

PHP中的隱式轉換機制解析 PHP中的隱式轉換機制解析 Mar 09, 2024 am 08:00 AM

PHP中的隱式轉換機制解析在PHP程式設計中,隱式轉換是指在不明確指定型別轉換的情況下,PHP會自動將一個資料型別轉換為另一個資料型別的過程。隱式轉換機制在程式設計中非常常見,但也容易造成一些意想不到的bug,因此了解隱式轉換機制的原理和規則對於編寫穩健的PHP程式碼非常重要。 1.整數與浮點型之間的隱式轉換在PHP中,整型和浮點型之間的隱式轉換是非常常見的。當一個整數

重要的JS快取機制概念:了解普及五個知識點 重要的JS快取機制概念:了解普及五個知識點 Jan 23, 2024 am 09:52 AM

知識普及:了解JS快取機制的五個重要概念,需要具體程式碼範例在前端開發中,JavaScript(JS)快取機制是一個非常關鍵的概念。理解並正確運用快取機制可以大幅提升網頁的載入速度和效能。本文將介紹JS快取機制的五個重要概念,並提供對應的程式碼範例。一、瀏覽器快取瀏覽器快取是指在第一次造訪網頁時,瀏覽器會將網頁的相關資源(例如JS檔案、CSS檔案、圖片等)保存

Go 語言中的記憶體管理機制是怎麼樣的? Go 語言中的記憶體管理機制是怎麼樣的? Jun 10, 2023 pm 04:04 PM

Go語言是一門廣泛用於系統層級程式設計的高效程式語言,其主要優勢之一是其記憶體管理機制。 Go語言內建的垃圾回收機制(GarbageCollection,簡稱GC)使得程式設計師不必親自進行記憶體分配和釋放操作,並提高了開發效率和程式碼品質。本文將對Go語言中的記憶體管理機制進行詳細介紹。一、Go記憶體分配在Go語言中,記憶體分配使用了兩個堆區:小物件堆(small

See all articles