[PHP]image_destroy()の挙動について調べてみた

Read More

PHP関数のimage_destroy()とは画像リソースを開放する関数。


この関数、ずいぶん昔に使った記憶がある。
けど、自作の画像を扱う関数のコードを覗いてみると…


あれ?
自作関数の中でimage_destroy()を使ってない。


でも以前使ったものを自分で消したんなら何か理由があったはず。
うーんなんでだったかなー。
時間があきすぎて思い出せない。


ってことでimage_destroy()がどんな挙動をするものなのか改めて調べてみた。


結論を先に言うと、画像生成処理に自作関数を使っている場合image_destroy()を使う必要はないってことがわかった。

まあ検証内容を以下に。



--
最初に適当な"1.png"って画像を同階層に用意しておくこと。


その1)
画像生成時のメモリの増え方

■image1.php
echo('start: ');
echo(number_format(memory_get_usage()).'Byte<br />');

// 画像の縦横幅を取得
list($new_width, $new_height) = getimagesize('1.png');

// キャンバスを作成
$canvas = imagecreatetruecolor($new_width, $new_height);

// キャンバスの背景を塗りつぶし
imagefill($canvas, 0, 0, 0xffffff);

// オリジナル画像の読み込み
$origin = imagecreatefrompng('1.png');

// 画像を複製
imagecopyresampled($canvas, $origin, 0, 0, 0, 0, $new_width, $new_height, $new_width, $new_height);
imagepng($canvas, '2.png');

echo('after a copy: ');
echo(number_format(memory_get_usage()).'Byte<br />');


■結果
start: 103,224Byte
after a copy: 2,526,016Byte


103KBから2.5MBまで一気に増えている。
その差約2.4MB!
ちなみに読み込んだ画像の大きさは500KB。

よく画像の生成にはマシンパワーを食うなんていわれてるけどこれ見ると本当っぽいね。



--
その2)
画像リソースの破棄によるメモリ変化

■image2.php
echo('start: ');
echo(number_format(memory_get_usage()).'Byte<br />');

// 画像の縦横幅を取得
list($new_width, $new_height) = getimagesize('1.png');

// キャンバスを作成
$canvas = imagecreatetruecolor($new_width, $new_height);

// キャンバスの背景を塗りつぶし
imagefill($canvas, 0, 0, 0xffffff);

// オリジナル画像の読み込み
$origin = imagecreatefrompng('1.png');

// 画像を複製
imagecopyresampled($canvas, $origin, 0, 0, 0, 0, $new_width, $new_height, $new_width, $new_height);
imagepng($canvas, '2.png');

echo('after a copy: ');
echo(number_format(memory_get_usage()).'Byte<br />');

// オリジナル画像の破棄
imagedestroy($origin);
echo('after destroyed origin: ');
echo(number_format(memory_get_usage()).'Byte<br />');

// キャンバスの破棄
imagedestroy($canvas);
echo('after destroyed canvas: ');
echo(number_format(memory_get_usage()).'Byte<br />');


■結果
start: 110,888Byte
after a copy: 2,533,096Byte
after destroyed origin: 1,322,200Byte
after destroyed canvas: 111,304Byte


先ほどのものにimage_destroy()をつけたもの。

PHP関数のimagecreatetruecolor()imagecreatefrompng() のそれぞれに大量のメモリが割り振られているもよう。

検証結果を見てもそのどちらにもimage_destroy()の効果があることがわかる。

約2.4MBほど膨れ上がったメモリがdestroyするごとに約1.2MB解放されており最終的には開始前とほぼ同じメモリに戻っている。



--
その3)
画像生成の処理を自作関数化したメモリの変化

echo('start: ');
echo(number_format(memory_get_usage()).'Byte<br />');
createImage();
echo('after a function: ');
echo(number_format(memory_get_usage()).'Byte<br />');

function createImage() {
  // 画像の縦横幅を取得
  list($new_width, $new_height) = getimagesize('1.png');

  // キャンバスを作成
  $canvas = imagecreatetruecolor($new_width, $new_height);

  // キャンバスの背景を塗りつぶし
  imagefill($canvas, 0, 0, 0xffffff);

  // オリジナル画像の読み込み
  $origin = imagecreatefrompng('1.png');

  // 画像を複製
  imagecopyresampled($canvas, $origin, 0, 0, 0, 0, $new_width, $new_height, $new_width, $new_height);
  imagepng($canvas, '2.png');

  echo('after a copy: ');
  echo(number_format(memory_get_usage()).'Byte<br />');
}// end function


■結果
start: 101,536Byte
after a copy: 2,524,184Byte
after a function: 102,024Byte


画像生成の処理をcreateImage()なる自作関数内に詰め込んだもの。

結果を見てもらえばわかるようにimage_destroy()をせずとも自作関数が終わったあとにメモリがほぼ平常値に戻っている。
まあ理由は言わずもがな。



--
これらの結果をまとめると、
・自作関数内などで画像生成した場合はimage_destroy()は必要ない。
・ベタで画像生成処理を書いた場合のみimagecreatetruecolor() と
imagecreatefrompng() にimage_destroy()が必要。
ということになる。

同様にimagecreatefromjpeg() や imagecreatefromgif() を使っている場合もそれらの画像リソースに対してimage_destroy()をする必要がある。


しかしまあ画像生成の一連の処理を関数化せずに使うことはないだろうからimage_destroy()は不要と覚えても問題なさそう。

もっとも、画像生成後も同一関数内で処理が続くようならimage_destroy()をする必要があるが。





--
あーあとどうでもいいけどキャンバスとキャンパスを間違えて使ってる人を何人かみたことがある。

キャンバス = canvas = 絵を描く画布
キャンパス = campus = 校庭
と違う。

バ(濁点)とパ(半濁点)は確かに似て見えるけど。
ちょっと気をつけたいところ。


まあ俺もビビンバとピビンパのどちらを使ったらいいのか悩むことがあるが。

世間一般でビビンバの方が浸透してしまってるのはキン肉マンのせいな気がする。