PHP カーネルで調べる変数 (1) Zval、カーネル zval_PHP チュートリアル
PHP カーネルで調査される変数 (1) Zval、カーネル zval
データのコンテナとして、変数が数値、配列、文字列、オブジェクトなどであるかどうかにかかわらず、変数を扱う必要があることがよくあります。変数は言語の不可欠な基礎を形成していると言われています。この記事は、PHP カーネルで検討される変数に関する最初の記事であり、主に次の側面を含む zval の基本的な知識を紹介します。
急いで書いているため、間違いがあるかもしれません、ご指摘ください。1. Zvalの基本構造
Zval は、PHP で最も重要なデータ構造の 1 つです (もう 1 つの重要なデータ構造は、PHP の変数の値と型に関する情報が含まれています)。これは構造体であり、基本的な構造は次のとおりです:
リーリー
その中に:
1. zval_value値
変数の実際の値、特に zvalue_value:の和集合 リーリー
2. zend_uint refcount__gc
この値は実際にはカウンターであり、変数 (またはシンボルsymbols) の数を保存するために使用されます。すべてのシンボルはシンボル テーブル (シンボル テーブル) に保存されます。異なるスコープでは異なるシンボル テーブルが使用されます。これについては、後で説明します。後で説明します) zval を指します。変数が生成されると、その refcount=1 になります。$a = $b などの一般的な代入操作では zval の refcount が 1 ずつ増加し、それに応じて unset 操作によって 1 ずつ減少します。 PHP5.3 より前では、GC の実装に参照カウント メカニズムが使用されていました。zval の refcount が 0 未満の場合、Zend エンジンは zval を指す変数が存在しないと判断し、その結果、zval が占有しているメモリ空間を解放していました。ズヴァル。しかし、物事はそれほど単純ではない場合もあります。 zval を指す変数が設定されていない場合でも、単純な参照カウント メカニズムでは循環参照された zval を GC できず、その結果メモリ リーク (メモリ リーク) が発生することが後でわかります。
3. zend_uchar型
このフィールドは、変数の実際の型を示すために使用されます。 PHP の学習を始めたとき、PHP の変数には4 つのスカラー型(bool、int、float、string)、2 つの複合型(配列、オブジェクト)、2 つの特殊型 (リソースと NULL) が含まれていることをすでに知っていました。 。 zend 内では、これらの型は次のマクロに対応します (コードの場所 phpsrc/Zend/zend.h): リーリー
4. is_ref__gc このフィールドは、変数が参照変数であるかどうかをマークするために使用されます。通常の変数の場合は値が 0、参照変数の場合は値が 1 になります。この変数は、zval の共有、分離などに影響します。これについては後で説明します。
名前が示すように、ref_count__gc と
is_ref__gcは、PHP の GC メカニズムに必要な 2 つの非常に重要なフィールドであり、これら 2 つのフィールドの値は、xdebug などのデバッグ ツールを通じて表示できます。 2. xdebugのインストールと設定
xdebug は、オープンソースの PHP パフォーマンス分析およびデバッグ ツールです。一般的なプログラムのデバッグには、
var_dump、echo、print、debug_backtrace およびその他の一般的なデバッグ ツールで基本的に十分ですが、一部の複雑なデバッグやパフォーマンス テストには、xdebug が間違いなく優れたヘルパーです (Xhprof などの他のツールも使用できます)素晴らしい)。 この記事の基本環境:
xdebug をインストールする基本プロセスは次のとおりです (実際にソース コードから拡張機能をコンパイルします)。
1. ソースコードパッケージをダウンロードします。
ダウンロードアドレスは http://www.xdebug.org/docs/install
この記事でダウンロードしたバージョンはxdebug-2.6.tar.gzです
2. 解凍します
リーリー 3. xdebug ディレクトリで phpize
を実行します。 4. ./configure 構成
5. 作成&&インストール
これにより、xdebug/modules にある xdebug.so 拡張ファイル (zend_extension) が生成されます
6. php.ini に xdebug 拡張機能をロードします
リーリー 7. xdebug 構成を追加します
リーリー 各設定項目の意味についてはここでは詳しく紹介しません。詳細については、http://www.xdebug.org/docs/all を参照してください。 これで、PHP には Xdebug 拡張情報 (php -m または phpinfo()) が存在するはずです。
これで、スクリプト内で、xdebug_debug_zval を通じて Zval 情報を出力できます: (注,本部分主要参考:http://derickrethans.nl/collecting-garbage-phps-take-on-variables.html, 作者Derick Rethans是一位优秀的PHP内核专家,在全世界做过多次报告,都有相关的pdf下载,这里(http://derickrethans.nl/talks.html )有作者每次演讲的记录,很多都值得我们深入去学习研究) 前面我们已经说过,PHP使用Zval这种结构来保存变量,这里我们将继续追踪zval的更多细节。 1. 创建变量时,会创建一个zval. 输出结果: 当使用$str="test zval";来创建变量时,会在当前作用域的符号表中插入新的符号(str),由于该变量是一个普通的变量,因此会生成一个refcount=1且is_ref=0的zval容器。也就是说,实际上是这样的: 2. 变量赋值给另外一个变量时,会增加zval的refcount值。 输出结果: 同时我们看到,str和是str2这两个symbol的zval结构是一样的。这里其实是PHP所做的一个优化,由于str和str2都是普通变量,因而它们指向了同一个zval,而没有为str2开辟单独的zval。这么做,可以在一定程度上节省内存。这时的str,str2与zval的对应关系是这样的: 结果为: 由于unset($str2,$str3)会将str2和str3从符号表中删除,因此,在unset之后,只有str指向该zval,如下图所示: 现在如果执行unset($str),则由于zval的refcount会减少到0,该zval会从内存中清理。这当然是最理想的情况。 但是事情并不总是那么乐观。 与标量这些普通变量不同,数组和对象这类复合型的变量在生成zval时,会为每个item项生成一个zval容器。例如: 打印出zval的结构是: 如下图所示: 可以看出,变量$ar生成的过程中,共生成了3个zval容器(红色部分标注)。对于每个zval而言,refcount的增减规则与普通变量的相同。例如,我们在数组中添加另外一个元素,并把$ar['name']的值赋给它: 则打印出的zval为: 如同普通变量一样,这时候,name和test这两个symbol指向同一个zval: 同样的,从数组中移除元素时,会从符号表中删除相应的符号,同时减少对应zval的refcount值。同样,如果zval的refcount值减少到0,那么就会从内存中删除该zval: 输出结果为: 在加入引用之后,情况会变的稍微复杂一点。例如,在数组中添加对本身的引用: 输出的结果: 上述输出中,…表示指向原始数组,因而这是一个循环的引用。如下图所示: 现在,我们对$a执行unset操作,这会在symbol table中删除相应的symbol,同时,zval的refcount减1(之前为2),也就是说,现在的zval应该是这样的结构: 也就是下图所示的结构: 这时,不幸的事情发生了! Unset之后,虽然没有变量指向该zval,但是该zval却不能被GC(指PHP5.3之前的单纯引用计数机制的GC)清理掉,因为zval的refcount均大于0。这样,这些zval实际上会一直存在内存中,直到请求结束(参考SAPI的生命周期)。在此之前,这些zval占据的内存不能被使用,便白白浪费了,换句话说,无法释放的内存导致了内存泄露。 如果这种内存泄露仅仅发生了一次或者少数几次,倒也还好,但如果是成千上万次的内存泄露,便是很大的问题了。尤其在长时间运行的脚本中(例如守护程序,一直在后台执行不会中断),由于无法回收内存,最终会导致系统“再无内存可用”。 前面我们已经介绍过,在变量赋值的过程中例如$b = $a,为了节省空间,并不会为$a和$b都开辟单独的zval,而是使用共享zval的形式: 那么问题来了:如果其中一个变量发生变化时,如何处理zval的共享问题? 对于这样的代码: 打印的结果是: 起初,符号表中a和b指向了同一个zval(这么做的原因是节省内存),而后$b发生了变化,Zend会检查b指向的zval的refcount是否为1,如果是1,那么说明只有一个符号指向该zval,则直接更改zval。否则,说明这是一个共享的zval,需要将该zval分离出去,以保证单独变化互不影响,这种机制叫做COW –Copy on write。在很多场景下,COW都是一种比较高效的策略。 那么对于引用变量呢? 输出的结果为: 可以看出,在改变了$b的值之后,Zend会检查zval的is_ref检查是否是引用变量,如果是引用变量,则直接更改即可,否则,需要执行刚刚提到的zval分离。由于$a 和 $b是引用变量,因而更改共享的zval实际上也间接更改了$a的值。而在unset($b)之后,变量$b从符号表中删除了。 这里也说明一个问题,unset并不是清除zval,而只是从符号表中删除相应的symbol。这样一来,之前很多的关于引用的疑问也可以理解了(下一节我们将深入探索PHP的引用)。
<?php
$a = array( 'test' );
$a[] = &$a;
xdebug_debug_zval( 'a' );
3. Zval的更多原理
$str = "test zval";
xdebug_debug_zval('str');
str: (refcount=1, is_ref=0)='test zval'
$str = "test zval";
$str2 = $str;
xdebug_debug_zval('str');
xdebug_debug_zval('str2');
str: (refcount=2, is_ref=0)=<span>'test zval'
str2: (refcount</span>=2, is_ref=0)='test zval'
3. 使用unset时,对减少相应zval的refcount值
$str = "test zval";
$str3 = $str2 = $str;
xdebug_debug_zval('str');
unset($str2,$str3)
xdebug_debug_zval('str');
str: (refcount=3, is_ref=0)=<span>'test zval'
str: (refcount</span>=1, is_ref=0)='test zval'
4. 数组变量与普通变量生成的zval非常类似,但也有很大不同
$ar = array(
'id' => 38,
'name' => 'shine'
); <br /><span>xdebug_debug_zval('ar');</span>
ar: (refcount=1, is_ref=0)=<span>array (
'id' </span>=> (refcount=1, is_ref=0)=38,<span>
'name' </span>=> (refcount=1, is_ref=0)=<span>'shine'
)</span>
$ar = array(
'id' => 38,
'name' => 'shine'
);
$ar['test'] = $ar['name'];
xdebug_debug_zval('ar');
ar: (refcount=1, is_ref=0)=<span>array (
'id' </span>=> (refcount=1, is_ref=0)=38,<span>
'name' </span>=> (refcount=2, is_ref=0)='shine',<span>
'test' </span>=> (refcount=2, is_ref=0)=<span>'shine'
)</span>
$ar = array(
'id' => 38,
'name' => 'shine'
);
$ar['test'] = $ar['name'];
unset($ar['test'],$ar['name']);
xdebug_debug_zval('ar');
ar: (refcount=1, is_ref=0)=array ('id' => (refcount=1, is_ref=0)=38)
5. 引用的出现,会令zval的规则变得复杂
$a = $array('one');
$a[] = &$a;
xdebug_debug_zval('a');
a: (refcount=2, is_ref=1)=<span>array (
</span>0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=<span>...
)</span>
(refcount=1, is_ref=1)=<span>array (
</span>0 => (refcount=1, is_ref=0)='one',
1 => (refcount=1, is_ref=1)=<span>...
)</span>
6. zval分离(Copy on write和change on write)
$a = "a simple test";
$b = $a;
echo "before write:".PHP_EOL;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
$b = "thss";
echo "after write:".PHP_EOL;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
<span>before write:
a: (refcount</span>=2, is_ref=0)=<span>'a simple test'
b: (refcount</span>=2, is_ref=0)=<span>'a simple test'
after write:
a: (refcount</span>=1, is_ref=0)=<span>'a simple test'
b: (refcount</span>=1, is_ref=0)='thss'
$a = 'test';
$b = &$a;<br />
echo "before change:".PHP_EOL;
xdebug_debug_zval('a');
xdebug_debug_zval('b');<br />
$b = 12;
echo "after change:".PHP_EOL;
xdebug_debug_zval('a');
xdebug_debug_zval('b');<br />
unset($b);
echo "after unset:".PHP_EOL;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
<span>before change:
a: (refcount</span>=2, is_ref=1)=<span>'test'
b: (refcount</span>=2, is_ref=1)=<span>'test'
after change:
a: (refcount</span>=2, is_ref=1)=12<span>
b: (refcount</span>=2, is_ref=1)=12<span>
after unset:
a: (refcount</span>=1, is_ref=0)=12
本文参考文献:

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

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

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

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

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

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

ホットトピック











PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHPとPythonにはそれぞれ独自の利点があり、プロジェクトの要件に従って選択します。 1.PHPは、特にWebサイトの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンス、機械学習、人工知能に適しており、簡潔な構文を備えており、初心者に適しています。

PHPは、電子商取引、コンテンツ管理システム、API開発で広く使用されています。 1)eコマース:ショッピングカート機能と支払い処理に使用。 2)コンテンツ管理システム:動的コンテンツの生成とユーザー管理に使用されます。 3)API開発:RESTFUL API開発とAPIセキュリティに使用されます。パフォーマンスの最適化とベストプラクティスを通じて、PHPアプリケーションの効率と保守性が向上します。

PHPは依然として動的であり、現代のプログラミングの分野で重要な位置を占めています。 1)PHPのシンプルさと強力なコミュニティサポートにより、Web開発で広く使用されています。 2)その柔軟性と安定性により、Webフォーム、データベース操作、ファイル処理の処理において顕著になります。 3)PHPは、初心者や経験豊富な開発者に適した、常に進化し、最適化しています。

PHPは主に手順プログラミングですが、オブジェクト指向プログラミング(OOP)もサポートしています。 Pythonは、OOP、機能、手続き上のプログラミングなど、さまざまなパラダイムをサポートしています。 PHPはWeb開発に適しており、Pythonはデータ分析や機械学習などのさまざまなアプリケーションに適しています。

PHPは、特に迅速な開発や動的なコンテンツの処理に適していますが、データサイエンスとエンタープライズレベルのアプリケーションには良くありません。 Pythonと比較して、PHPはWeb開発においてより多くの利点がありますが、データサイエンスの分野ではPythonほど良くありません。 Javaと比較して、PHPはエンタープライズレベルのアプリケーションでより悪化しますが、Web開発により柔軟性があります。 JavaScriptと比較して、PHPはバックエンド開発により簡潔ですが、フロントエンド開発のJavaScriptほど良くありません。

PHPとPythonには独自の利点と短所があり、選択はプロジェクトのニーズと個人的な好みに依存します。 1.PHPは、大規模なWebアプリケーションの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンスと機械学習の分野を支配しています。
