EXIF 情報の仕様書
- 2006年 6月21日
- 投稿者 : ino
カテゴリー : 2006年 6月
大したことではありませんが、ふと気づいたのでメモしておきます。
検証環境: PHP 4.4.2
時間, メモリ量のリミットなし
なお、都合により memory_get_usage() ではなく top コマンドでメモリ消費を確認しています。
$n = 5; // sleep する秒数
echo “Started..\n”;
$a = str_repeat(“a”, 1024 * 1024 * 10); // 10MB
sleep($n); // #使用量 13MB
echo “Cloning \$a into \$b.\n”;
$b = $a; // コピー
sleep($n); // #使用量..変化なし ←この時点では参照($b=&$a)と同等
echo “Modifing \$a.\n”;
$a{0} = ‘b’; // $a の 0 文字目を ‘b’ に変更
sleep($n); // #使用量..23MB ←一方が変更されて始めてバッファが複製される
echo “Freeing \$a.\n”;
$a = null; // 解放
sleep($n); // #使用量..13MB
echo “Referring \$b for \$c \n”;
$c =& $b; // 参照
sleep($n); // #使用量..変化無し
echo “Modifing \$b.\n”;
$b{0} = ‘c’; // $b の 0 文字目を ‘c’ に変更
sleep($n); // #使用量..変化無し
echo “Freeing memory for \$b (and also \$c)\n”;
$b = null; // 解放
sleep($n); // #使用量..3MB
この検証でわかるのは、単純な代入の場合は、代入元、代入先いずれかが変更されるまでは参照と同等に処理する(つまりメモリ確保や strcpy をしない)ということです。
上の例のように変数の値を捨てたり unset したりして明示的にメモリを解放してやらなくても、変数が関数の終了でスコープアウトした時点で自動的に解放されます。
ただし、Chain of Repository Pattern など、メソッド、関数の呼び出しが連鎖する場合は、呼び出し先の関数が終了するまで、呼び出し元の関数内の変数も存在し続ける事に注意が必要です。
$a = str_repeat(“a”, 1024 * 1024 * 10);
// 3 段の連鎖(※1)
$o = new Chain(1,
new Chain(2,
new Chain(3, null)
)
);
$o->handle($a); // 連鎖実行。
// ↑ここだけで最終的に Chain の段数 x strlen($a) バイトのメモリを消費する!!
echo “Finished\n”;sleep(6);
echo substr($a, 0, 100).”\n”;
exit;
// ——————————–
// Chain Of Repository パターンの簡単な実装
class Chain{
var $v;
var $_next;
function Chain($v, $next = null){
$this->v = $v;
$this->_next = $next;
}
function next(&$buf){
if(!empty($this->_next)) $this->_next->handle($buf);
}
function handle(&$buf){
echo “Step:{$this->v}\n”;
// $buf に使って何らかの処理をし、結果を $res に格納。
$res = $this->v.$buf;
$buf = $res; // $buf を処理結果に置き換え。
sleep(5); // (※2)
$this->next($buf); // 次の処理へ($res が生きている)。
}
}
この Chain クラスでは(※1)を重ねれば重ねるほどメモリ利用量が増え続け、handle が全て完了するまで解放されないという一種のメモリリークが発生しています。
これを解消するには(※2) の箇所で $res = null などで解放を明示してやる必要があります。
http://xmlgraphics.apache.org/batik/
例えば次の用途で利用可能です。
- CUI で SVG をラスタライズして JPEG, PNG 画像に変換する。
- Java アプレットなどで SVG 形式のベクタ画像データを処理する。
HTTP_Client が 1.1 になって get/post 時に <meta http-equiv=’Refresh’> のリダイレクトをたどってくれるようになりました。
(ChangeLogより抜粋)
* HTTP_Client now analyzes the response body for <meta http-equiv=”Refresh”>
tags and follows the redirects defined in them (request #5734)
便利になっていいのですが、このアップデート以降 “Fatal Error: Too many redirects” というエラーが出るようになりました。_maxRedirects の値に達するまで延々と同じURLをアクセスし続けて、その結果発生しているようです。
別の環境での再現を確認していないのですが、この現象は <meta http-equiv=”Refresh” contents=”…;url=/path/to/nextPage”> を利用しているサイトで post() でリクエストすると発生するようです(post($url.$query, array()) も不可)。全く同じコードでget() に置き換えると問題なく動作しました。
http_build_query() で連想配列/配列から HTTP の GET/POST クエリ文字列を生成、parse_str() でHTTP の GET/POST クエリ文字列を解析(パース/パーズ)して連想配列にすることができます。
※GET/POSTクエリ文字列というのは key1=value1&key2=value2&… という形式の文字列を指します。
string http_build_query(array formdata [, string numeric_prefix])
void parse_str(string str [, array &arr])