現在の言語: 日本語

戻る

nullとunsetについて
メモリ解放関連

nullとunsetについて
メモリ解放のタイミングについて
unset関数とnullを設定する場合にはタイミングの違いがあります。

項目unset()$data = null;
目的指定した変数の割当を解除します。
シンボルテーブルから削除します。
変数にnullという特殊な値を代入します。
変数は存在を継続しています。
メモリ解放変数が参照されなくなるとガベージコレクションによって
非同期的にメモリが解放されます。
変数が保持していたデータへの参照が直ちになくなります。
より早くメモリが解放される可能性があります。
CPU負荷ガベージコレクションにま変えるため、
CPUサイクルは節約されます。
データの上書きとメモリ解放の処理が発生します。
CPUサイクルを消費しやすくなります。
処理変数自体が存在しなくなります。
以降、該当する変数にアクセスすると
Undefined variableのNoticeが発生します。
変数を一時的に値がない状態にしたい場合
オブジェクトの参照カヌンとを減らして早期にメモリを解放したい場合

[null]
参照を切断したい場合、変数は残ります。

[unset()]
変数を完全に破棄したい場合


[サンプル]

copy
class test1
{
	public $child;
	public $name;
	
	public function __construct($name) {
		$this->name = $name;
		echo "オブジェクト {$this->name} が作成されました\n";
	}
	
	// デストラクタ:オブジェクトがメモリから解放される直前に呼ばれる
	public function __destruct() {
		echo "オブジェクト {$this->name} が破棄されました\n";
	}
}
echo "<pre>";

$a = new test1("A");//オブジェクト A が作成されました
$b = new test1("B");//オブジェクト B が作成されました

// ----------------------------------------------------
// 循環参照を設定
// ----------------------------------------------------
$a->child = $b;
$b->child = $a;

// ----------------------------------------------------
//解放処理
// ----------------------------------------------------

$a = null;
echo "\$a を null に設定しました。\n"; 
//$aの参照が切断されます
//オブジェクトAのデストラクタが呼ばれ、メモリの解放が始まります。

unset($b);
echo "\$b を unset しました。\n";
//$bの参照が切断されます
//オブジェクトBのデストラクタが呼ばれ、メモリ解放が完了します。
echo "</pre>";
copy
class test1
{
	public $child;
	public $name;
	
	public function __construct($name) 
	{
		$this->name = $name;
		echo "Object {$this->name} was created\n";
	}
	
	/ Destructor: Called just before an object is released from memory.
	public function __destruct() 
	{
		echo "Object {$this->name} was destroyed\n";
	}
}
echo "<pre>";

$a = new test1("A"); // Object A was created.
$b = new test1("B"); // Object B was created.

// ----------------------------------------------------
// Establish a circular reference.
// ----------------------------------------------------
$a->child = $b;
$b->child = $a;

// ----------------------------------------------------
// Release process.
// ----------------------------------------------------

$a = null;
echo "\$a to null" \n";
//The reference to $a is broken.
//The destructor for object A is called, and memory release begins.

unset($b);
echo "\$b has been unset. \n";
//The reference to $b is broken.
//The destructor for object B is called, and memory release is complete.
echo "</pre>";



$a = null;
オブジェクトAとBの間の循環参照が切断されます。
これにより、オブジェクトAのメモリの解放が始まります。
もしも、$a = null;のようにnullを設定して参照を解放しないで
unset($a);のみを実行した場合は
循環参照を即時解決できません。
そのため、メモリ解放が遅延する可能性があります。

このように循環参照を視野に入れるケースでは
参照を切断するために変数にnullを設定してから
unset(変数)のように実行する手順を実行する方法をとることになります。

copy
class test2
{
	function test1()
	{
		$a = 100; // $a が 100 として存在します
		$a++;     // $a は 101 になります
		echo $a;  // 101 が出力されます
		
		unset($a); // ここで $a は完全に消滅します
		
		$a = null; // 新しく$aという変数をnullで宣言し直しています
	}
	function test2()
	{
		$a = 100; // $a が 100 として存在します
		$a++;     // $a は 101 になります
		echo $a;  // 101 が出力します
		
		$a = null; // $aの参照が切断されます(変数としては残っています)
		unset($a); // 変数を削除します

	}
	function test3(int &$data)
	{
		$data = null;
		unset($data);

	}
	function test4(int &$data)
	{
		// 値をnullにする操作だけを行う
		$data = null;//値を消しています
		//test3のように、ここではunsetを実行しないようにします
		//unset($data);
	}
}
echo "<pre>";

$cls2 = new test2();
$cls2->test1();
$cls2->test2();
$a = 100;
$cls2->test3($a);
$a = 101;
$cls2->test4($a);
unset($a);//ここで実行します


echo "</pre>";
copy
class test2
{
	function test1()
	{
		$a = 100; // $a exists as 100
		$a++; // $a becomes 101
		echo $a; // 101 is output
		
		unset($a); // $a is completely destroyed here
		
		$a = null; // A new variable called $a is declared as null
	}
	function test2()
	{
		$a = 100; // $a exists as 100
		$a++; // $a becomes 101
		echo $a; // 101 is output
		
		$a = null; // The reference to $a is severed (it remains as a variable)
		unset($a); // The variable is deleted
	
	}
	function test3(int &$data)
	{
		$data = null;
		unset($data);
	
	}
	function test4(int &$data)
	{
		//Only nullify the value.
		$data = null; //Delete the value.
		//Unset is not executed here, as in test3.
		//unset($data);
	}
}
echo "<pre>";

$cls2 = new test2();
$cls2->test1();
$cls2->test2();
$a = 100;
$cls2->test3($a);
$a = 101;
$cls2->test4($a);
unset($a); //Execute here.

echo "</pre>";
$cls2->test3($a);
$dataは引数として受け取った$aと同じ場所を見ています。
$data = null;
参照渡し(&)にしているため
$dataにnullを設定することで$aもnullに書き換えられます。
unset($data);
$dataと参照しているメモリ領域の結びつきを切断します。
unsetを実行することで関数内の$dataは消滅します。
しかし、unsetは関数内で実行されているため
関数外の$a変数には影響せず、$a変数自体が残ってしまします。
そのためtest4のようにunsetの実行は関数外で行います。

$cls2->test4($a);
test4関数内でunsetは実行させません。
関数を実行後に、呼び出し元のスコープでunsetを実行することで
変数を完全に削除することができます。



戻る

著作権情報
ホームページおよプリ等に掲載されている情報等については、いかなる保障もいたしません。
ホームページおよびアプリ等を通じて入手したいかなる情報も複製、販売、出版または使用させたり、
または公開したりすることはできません。
当方は、ホームページおよびアプリ等を利用したいかなる理由によっての障害等が発生しても、
その結果ホームページおよびアプリ等を利用された本人または他の第三者が被った損害について
一切の責任を負わないものとします。