[PHP-users 10167] リソース変数の開放のタイミング

桝形 誠二 php-users@php.gr.jp
Tue, 17 Sep 2002 17:46:37 +0900


こんにちわ、桝形です。

PHPのリソース変数の開放のタイミングについて色々と調べているの
ですが、少々分からない事があり質問させてもらいます。

明示的にmysql_close処理を行わない方が、若干ですが処理速度が
向上したという結果から、実際にソースコードを確認してみました。

ここで既に考え方が間違っていたら、ご指摘願います。

ちなみに、これを確認したのはApacheに付属しているabです。
------------------------------------------------------------------
(PHP4.2.3ソースディレクトリ)/ext/mysql/php_mysql.c

265行目〜

static void _close_mysql_link(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
	php_mysql_conn *link = (php_mysql_conn *)rsrc->ptr;
	void (*handler) (int);   

	handler = signal(SIGPIPE, SIG_IGN);
	mysql_close(&link->conn);
	signal(SIGPIPE, handler);
	efree(link);
	MySG(num_links)--;
}

365行目

le_link = zend_register_list_destructors_ex(_close_mysql_link, NULL, "mysql link", module_number);
------------------------------------------------------------------

PHPの変数では、参照されなくなったり、不要となった場合に自動的
にデストラクタが起動され、このデストラクタにより変数が削除され
使用しているメモリが開放されると青マンモス本から理解しました。

上記の仕組みで、最終的にリソース変数を削除しようとした際に
デストラクタハンドラ関数がコールされ、mysql_close処理が実行
されるというからくりになっている事を確認しました。

よって、マニュアルの説明通り特に記述しなくても開放は行うと
いう事は理解できました。

青マンモス本には非常にお世話になっております、感謝です。(^^;

では、なぜ明示的にmysql_close処理を行うと処理速度に影響がでるのか?
と思い、再度ソースを確認してみました。
------------------------------------------------------------------
750行目〜( mysql_closeによって行われる処理 )

PHP_FUNCTION(mysql_close)
{
	zval **mysql_link=NULL;
	int id;
	php_mysql_conn *mysql;

	switch (ZEND_NUM_ARGS()) {
		case 0:
			id = MySG(default_link);
			break;
		case 1:
			if (zend_get_parameters_ex(1, &mysql_link)==FAILURE) {
				RETURN_FALSE;
			}
			id = -1;
			break;
		default:
			WRONG_PARAM_COUNT;
			break;
	}
	
	ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, id, "MySQL-Link", le_link, le_plink);

	if (id==-1) { /* explicit resource number */
		zend_list_delete(Z_RESVAL_PP(mysql_link));
	}

	if (id!=-1 
		|| (mysql_link && Z_RESVAL_PP(mysql_link)==MySG(default_link))) {
		zend_list_delete(MySG(default_link));
		MySG(default_link) = -1;
	}

	RETURN_TRUE;
}
------------------------------------------------------------------
実際には、zend_list_deleteをコールしているだけで、mysql_close
処理を行っているようには見受けられませんでした。

ただ、ZEND_FETCH_RESOURCE2というマクロによってリソースの実体を
取得してから削除の処理を行っているので、それが影響しているのかな?
と推測しました。ここでも考え方が間違っていたら指摘して下さい。

http://jp2.php.net/manual/ja/function.mysql-connect.php
の、マニュアルで、

サーバーへのリンクは、mysql_close()のコールにより明示的に
閉じられない限り、スクリプトの実行終了と同時に閉じられます。 

と、あるので実はどこかでデストラクタハンドラ関数をコール
しているのでは?と推測し、zend_list_deleteを追っていったの
ですがそこで追えきれなくなりSTOPしてしまいました。

zend_list_delete→zend_hash_index_del→zend_hash_del_key_or_index

ちなみにPostgreSQLモジュールも似たような処理になっている
事をソースコードから確認しました。

http://ns1.php.gr.jp/pipermail/php-users/2002-July/008706.html
辺りでの内容がよく理解できなかった為に、似たような質問に
なってしまい大変恐縮なのですが。。。

上記では、

> zvalのrefcountが0になった次のopコードで、ほとんどの場合、
> リリースされます。
> 
> # zvalとはPHP(ZendEngine)の変数を格納する構造体です。
> 
> <?php
> $var = "text"; // zval points to $var has refcount = 1
> $foo = $var;   // the zval has refcount = 2 now
> 
> unset($var);   // the zval has refcount = 1
> unset($foo);   // the zval has refcount = 0
> 
> call_some_function(); // the zval is cleaned up before calling it
> ?>

と、あるので、

<?php
$var = "text"; // zval points to $var has refcount = 1
$foo = $var;   // the zval has refcount = 2 now
unset($var);   // the zval has refcount = 1
mysql_close( ); // ここでは、デストラクタハンドラ関数はコールされない?
unset($foo);   // the zval has refcount = 0
mysql_close( ); // ここで、デストラクタハンドラ関数はコールされる?
?>

という事になるのでしょうか?
識者の方、ご教授願います。m(_ _)m

【環境】

OS    :RedHatLinux6.2J
Apache:1.3.26
PHP   :4.2.2( 国際化版 )
DB    :MySQL3.23.52
_______________________

  桝形 誠二( Masugata Seiji )
  E-Mail : s.masugata@digicom.dnp.co.jp

 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄