大きな配列の変換処理にunsetが無い

  • ページ: BugTrack2
  • 投稿者: ko-zu
  • 優先順位: 低
  • 状態: 完了
  • カテゴリー: 本体バグ
  • 投稿日: 2006-02-02 (木) 01:28:01
  • バージョン:

関連

修正

  • cvs:lib/backup.php (1.11): BugTrack2/159: Just free used memory chunks when copying memory to memory (Patched by ko-zu)
    • あるページのバックアップデータを操作する際、最大でバックアップデータの二倍の量のメモリを確保していた部分について、一倍 + 一履歴分となるように修正

メッセージ

BugTrack/732メモリ制限周りの問題を見たのですが、データの配列を全コピーしている所で逐一unsetが必要かと思われます。

  • make_backup()
     	foreach($backups as $age=>$data) {
     		$strout .= PKWK_SPLITTER . ' ' . $data['time'] . "\n"; // Splitter format
     		$strout .= join('', $data['data']);
    +		unset($backups[$age]);
     	}
     	$strout = preg_replace("/([^\n])\n*$/", "$1\n", $strout);
  • get_backup()
     	$regex_splitter = '/^' . preg_quote(PKWK_SPLITTER) . '\s(\d+)$/';
    -	foreach($lines as $line) {
    +	foreach($lines as $key => $line) {
                 中略
    +		unset($lines[$key]);
     	}
    一応この手のメモリピークの元になりそうな所を探してみましたが、他の本体ライブラリにはなさそうです。

簡単なメモリ測定関数を作って遊んでいたところ、(解凍後の)実データの5倍近くメモリ喰ってたもので作成。パッチでメモリ使用量ピークは半減、負荷が微増…

数kBくらいのページでも頻繁に更新すればバックアップは1メガいきますし、 大容量投稿で案外簡単に攻撃できそう、と思ったら実は難しい?

  • gzfile内部のメモリピークをターゲットに、バックアップ読み込み時でメモリリミットを選択的に発動!というように攻撃出来るか試してますが、あまりうまくいってません。diffがメモリとCPUをくうため投稿に失敗する… (^^;
    • ローカル(CPUが十分速い)の実験では投稿内容をうまく選べば、まれに成功してしまうこともあるみたいなので、十分試行錯誤すれば出来そうな予感。

投稿時やバックアップ書込時の記事サイズ判定を導入した方が良いかもしれません。 *1

検証…3.4MBのソース(1MB*2の投稿三回分として)をgz圧縮してget_backupに読ませてみました。 メモリ測定はforeachループ脱出直後に設置、スキン中で出力。

Memory Usage 22114 kbytes, in get_backup. // パッチ前
Memory Usage 12124 kbytes, in get_backup_unset. // 測定直前にunset
Memory Usage 12528 kbytes, in get_backup_patch. // あててみる

配列が10Mのメモリを占有…恐怖。

  • ちなみに4MBくらいの改行の多いファイルにすると、40MBのmemolylimitを突破します。 どうやら内部のgzfileが喰っているようです。fopenして必要な長さずつ文字列に取り込んでしまった方がいいような気がします。 *3

  • 興味深いですね :) メモリ喰ってそうな処理が色々あることは分かっているのですが、今まで深く検証されたことがないような気がします。 -- teanan 2006-02-02 (木) 09:47:29
  • こんにちは :) 投稿ありがとうございます。teananさんの言う通りで、実地で色々調べた例は少ないのでとても有り難いです。また編集時の処理は特に見直しの足りない部分のひとつで、このsf.jpの環境に来てやっとみんな目が向いてきた様な状況です*4。どちらも、不要になったメモリを順次開放しているだけであり、全く問題無いと思います。 -- henoheno 2006-02-02 (木) 21:53:48
    • 既にコメントにある通り、さらに改善する余地はあると思います。本当に直すならfopen/gzopenを使ったものに書き直して、必要な最小限のデータだけをメモリに格納したり、まさに必要なデータ構造だけを速やかに作成するよう直すのが良いと思います。ひとまずこれで状況が少し改善しそうですね :) -- henoheno 2006-02-02 (木) 22:07:42
    • ということで cvs:lib/backup.php (1.11) -- henoheno 2006-02-02 (木) 22:29:03
    • official, dev にも適用しました。(devはCVS版と同じ状態になりました) -- henoheno 2006-02-02 (木) 22:36:17
  • こちらも完了にしておきます。 -- henoheno 2006-06-18 (日) 23:37:48
  • その「簡単なメモリ測定関数」ってどうやって書くのでしょう?調べてみたい -- 2006-06-22 (木) 04:05:29

余談: get_backupの最適化に挑戦

  • 対応どもです。get_backupを最適化*5に挑戦してますが、streamや追加引数使ってほとんど総書き換え中です。pukiwikiは全部streamではなくgzに置き換えてますが何か問題在るんでしょうか? 一応動きそうなコード -- ko-zu 2006-02-04 (土) 13:46:15
    • 正規表現の\sは改行を含むので' '半角スペースに固定してます。他にもタブとか必要なのでしょうか? あと、改行処分はpregを使わずrtrim($body,"\n") . "\n" で高速化になるような気が。 -- ko-zu 2006-02-04 (土) 17:36:57
  • こちらの件、ついていけておらず申し訳ありません。話題別に、切りのいい所でBugTrackを立ち上げていただく方が良いでしょう -- henoheno 2006-06-18 (日) 23:39:38


*1 あとPukiWiki2ではバックアップは結合無しかサイズで小分けに1票。それだけでだいぶ違うのでは
*2 だいたいこれぐらいが投稿の限界かと思われます
*3 PHP初級者なんで叩いたってくださいな。
*4 「ハードウェア換えろ」という意見も目立ちましたが・・(^^;
*5 文字列処理にして、無駄なメモリを喰うpreg_matchをpreg_splitに置き換える

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-03-08 (月) 12:14:38
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.182 sec.

OSDN