PHPのメモリ管理について(値渡し)
notoです。
PHPのメモリ管理はどういう仕組みで動いているのか少し調べてみたので、その検証です。
PHPの変数管理については、「はじめに-PHP変数管理解説(1)-参照と値渡しの明確な理解のために」がわかりやすくまとまっていると思うので、初めに目を通したほうがいいと思います。
zvalの確認方法
zvalの中身を確認するには、debug_zval_dump関数とxdebug_debug_zval関数があります。
xdebug_debug_zval関数はリファレンスカウンタも表示してくれますので、こちらを利用します。
※xdebug_debug_zval関数を利用するには、xdebugをインストールする必要があります。
値渡しと参照渡し
値渡しと参照渡しはどう管理されているのか確認していきます。
値渡しサンプル
<?php $hoge = 'ほげ'; $piyo = $hoge; xdebug_debug_zval('hoge'); xdebug_debug_zval('piyo');
この実行結果はどうなるでしょうか。
シンボルテーブル
変数名 | zval No |
---|---|
hoge | #0001 |
piyo | #0002 |
zval
No | Value | refcount | is_ref |
---|---|---|---|
#0001 | ほげ | 1 | 0 |
#0002 | ほげ | 1 | 0 |
こうだと思った方はもう一度、はじめに-PHP変数管理解説(1)-参照と値渡しの明確な理解のためにを読みなおしてください。
実行結果
hoge: (refcount=2, is_ref=0)='ほげ' piyo: (refcount=2, is_ref=0)='ほげ'
シンボルテーブル
変数名 | zval No |
---|---|
hoge | #0001 |
piyo | #0001 |
zval
No | Value | refcount | is_ref |
---|---|---|---|
#0001 | ほげ | 2 | 0 |
この時、refcount=2となっています。refcountは、zvalコンテナがシンボルテーブルといくつリンクしているかを表しています。
これだと参照渡しに見えますよね。では、変数 piyoに値を代入してみます。
<?php $hoge = 'ほげ'; $piyo = $hoge; xdebug_debug_zval('hoge'); xdebug_debug_zval('piyo'); echo 'piyoに値を代入', PHP_EOL; $piyo = 'ぴよ'; xdebug_debug_zval('hoge'); xdebug_debug_zval('piyo');
実行結果
hoge: (refcount=2, is_ref=0)='ほげ' piyo: (refcount=2, is_ref=0)='ほげ' piyoに値を代入 hoge: (refcount=1, is_ref=0)='ほげ' piyo: (refcount=1, is_ref=0)='ぴよ'
シンボルテーブル
変数名 | zval No |
---|---|
hoge | #0001 |
piyo | #0002 |
zval
No | Value | refcount | is_ref |
---|---|---|---|
#0001 | ほげ | 1 | 0 |
#0002 | ぴよ | 1 | 0 |
変数 piyoに値を代入する前は同じzvalコンテナとリンクしていましたが、代入された後は新たに「ぴよ」という値が書き込まれたのが確認できます。
PHPの値渡しはこういう仕組みで動いていたんですね。そもそもシンボルテーブルの存在すら知りませんでした。。。
少し長くなってしまったので次回に参照渡しの検証について書きます。
おーこれは確かに重要ですね。
値コピーで無意識に参照カウントしてるとかしらんかったー。
ちなみにPerlではリファレンスという機能があって意図的に参照カウントを操作できるので
頭悩ますことは無いのですよー。Perlかわいくなってきたよ。
phpもperlもガベージコレクションには、リファレンスカウント方式を使用してるから、循環参照は気をつけなくてはいけないね。
perfect vimmerになってきたか(笑)