PHP的垃圾回收机制详解
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中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加。但是在平常的(更小的)脚本中应根本就没有性能影响。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









CSS のリフローと再描画は、Web ページのパフォーマンスの最適化において非常に重要な概念です。 Web ページを開発する場合、これら 2 つの概念がどのように機能するかを理解すると、Web ページの応答速度とユーザー エクスペリエンスを向上させることができます。この記事では、CSS のリフローと再描画の仕組みを詳しく説明し、具体的なコード例を示します。 1. CSS リフローとは何ですか? DOM 構造内の要素の表示、サイズ、位置が変更されると、ブラウザは CSS スタイルを再計算して適用し、再レイアウトする必要があります。

一部のユーザーがコンピューターを使用すると、Win10 システムがジャンクをクリーンアップします。Win10 システムがジャンクをクリーンアップする問題に遭遇した場合、どのように解決すればよいでしょうか?現在、Win10 システムのゴミをクリーンアップする状況に対処する方法がわからないユーザーがまだ多いため、Win10 でシステムのゴミをクリーンアップするためのステップバイステップのチュートリアルを見てみましょう。一緒に見てください。 1. コンピュータのデスクトップで「この PC」をクリックして管理します。 2. [ディスクの管理] を選択します。 3. クリーニングするディスクを選択し、右クリックして [プロパティ] を選択します。 4. ページの下部にある [ディスク クリーンアップ] ボタンをクリックします。 5. 表示されるインターフェイスで、クリーンアップするファイルを選択し、[OK] をクリックし、[ファイルの削除] をクリックします。上記は、Windows 10 でシステムのジャンクをクリーンアップする方法に関するステップバイステップのチュートリアルです。

PHP 言語の人気が高まるにつれて、開発者はより多くのクラスや関数を使用する必要があります。プロジェクトのサイズが大きくなると、すべての依存関係を手動で導入するのは現実的ではなくなります。現時点では、コードの開発とメンテナンスのプロセスを簡素化するために、自動読み込みメカニズムが必要です。自動ロード メカニズムは、実行時に必要なクラスとインターフェイスを自動的にロードし、手動によるクラス ファイルの導入を減らすことができる PHP 言語の機能です。このようにして、プログラマーはコードの開発に集中でき、面倒な手動のクラス導入によって引き起こされるエラーや時間の無駄を減らすことができます。 PHPでは一般的に、

タイトル: Golang 変数の保存場所とメカニズムの詳細な調査 Go 言語 (Golang) の応用がクラウド コンピューティング、ビッグ データ、人工知能の分野で徐々に増加するにつれて、特に重要です。 Golang 変数の保存場所とメカニズムを深く理解します。この記事では、Golang における変数のメモリ割り当て、保存場所、および関連するメカニズムについて詳しく説明します。具体的なコード例を通じて、Golang 変数がメモリ内でどのように保存および管理されるかを読者がより深く理解できるようにします。 1.Golang変数の記憶

Go 言語 (Golang とも呼ばれる) は、同時実行性やガベージ コレクション メカニズムなどの機能を備えた、Google によって開発された効率的なプログラミング言語です。この記事では、Go言語のガベージコレクションの仕組みについて、その原理や実装方法、コード例などを含めて詳しく解説します。 1. ガベージコレクションの原理 Go 言語のガベージコレクション機構は、「マーククリア」アルゴリズムによって実装されています。プログラムの実行中、Go ランタイムは、ヒープ内のどのオブジェクトにアクセスできる (マークされている) か、どのオブジェクトにアクセスできないか、つまりガベージ データ (クリアする必要がある) を追跡します。

PHP における暗黙的な変換メカニズムの分析 PHP プログラミングにおいて、暗黙的な変換とは、型変換を明示的に指定せずに、PHP が 1 つのデータ型を別のデータ型に自動的に変換するプロセスを指します。暗黙的な変換メカニズムはプログラミングでは非常に一般的ですが、予期せぬバグを引き起こしやすいため、暗黙的な変換メカニズムの原理とルールを理解することは、堅牢な PHP コードを作成するために非常に重要です。 1. 整数型と浮動小数点型の間の暗黙的な変換 PHP では、整数型と浮動小数点型の間の暗黙的な変換が非常に一般的です。整数の場合

知識の普及: JS キャッシュ メカニズムの 5 つの重要な概念を理解します。具体的なコード例が必要です。フロントエンド開発では、JavaScript (JS) キャッシュ メカニズムは非常に重要な概念です。キャッシュ メカニズムを理解して正しく適用すると、Web ページの読み込み速度とパフォーマンスを大幅に向上させることができます。この記事では、JS キャッシュ メカニズムの 5 つの重要な概念を紹介し、対応するコード例を示します。 1. ブラウザ キャッシュ ブラウザ キャッシュとは、Web ページに初めてアクセスしたときに、ブラウザが Web ページの関連リソース (JS ファイル、CSS ファイル、画像など) を保存することを意味します。

Go 言語は、システムレベルのプログラミングに広く使用されている効率的なプログラミング言語であり、その主な利点の 1 つはメモリ管理メカニズムです。 Go 言語に組み込まれているガベージ コレクション メカニズム (GarbageCollection、GC と呼ばれる) により、プログラマが自らメモリ割り当てや解放操作を実行する必要がなくなり、開発効率とコード品質が向上します。この記事では、Go 言語のメモリ管理メカニズムについて詳しく説明します。 1. Go のメモリ割り当て Go 言語では、メモリ割り当てには 2 つのヒープ領域が使用されます。
