2010-10-20追記
関連POST
PHPExcel1.7.4の不具合?について
===============
PHPExcelのシート追加でメモリをガンガン消費しちゃう件。
リンク先を参考に解析。
SE奮闘記: 【PHP】PHPExcelがループ内でメモリを使いすぎる
ワーク シート数 | メモリ使用量(Byte) | |
---|---|---|
改善前 | 改善後 | |
1 | 21,233,664 | 21,233,664 |
2 | 22,544,384 | 22,544,384 |
3 | 25,165,824 | 23,855,104 |
4 | 30,408,704 | 24,903,680 |
5 | 40,632,320 | 25,952,256 |
6 | 60,293,120 | 27,262,976 |
7 | 100,139,008 | 28,311,552 |
8 | 180,092,928 | 29,360,128 |
9 | 340,000,768(推定) | 30,408,704 |
10 | 659,816,448(推定) | 31,457,280 |
改善前 $aSheet = $this->excel->getActiveSheet(); for ($i = 0; $i < count($this->data); $i++) { if ($i != 0) { $this->excel->addSheet(clone $aSheet); } }
改善後 $aSheet = $this->excel->getActiveSheet(); $newSheets = array(); for ($i = 0; $i < count($this->data); $i++) { if ($i != 0) { $newSheets[] = clone $aSheet; } } foreach ($newSheets as $newSheet) { $this->excel->addSheet($newSheet); }
改善前は大体次の数式のようにメモリ使用量が増えていってるっぽくてO(2^n)のオーダー(かな?)
f(n+1) = 2.5MB * 2^(n+1) + f(n)
改善後は次の数式でO(n)のオーダー。
f(n) = 1.25MB * n + 20MB
リンク先で触れられていた「シートをコピーして追加する」の処理をやめて「テンプレートからシートを流し込むとよい」という内容は確認できませんでした。
リンク先とは状況が違うとは思いますが、こちらの解析ではPHPExcel_Worksheetを__cloneする時にメモリがどんどん消費されていっているらしくて、PHPExcel_Worksheet#copy()も内部的には__cloneを呼んでいる。
だからと言って、
$this->excel->addSheet(clone $aSheet);
が
$newSheets[] = clone $aSheet;
になったことでそんなに劇的に変わる理由がよく分かりませんが、
$aSheet = $this->excel->getActiveSheet();
した$aSheetが指しているactiveなシートの参照先が
$this->excel->addSheet(clone $aSheet);
したことによってどうにかなってしまったんではなかろうか、と想像。
PHPExcelの実装の問題なのか、cloneする変数の参照先の親オブジェクトにループ内でメンバ変数追加するとそうなってしまうPHPの仕様なのか、何とも言えませんが、今後の為にメモ。