目次
はじめに
PHPの配列や文字列は、代入や関数の引数で渡すときにいきなりメモリをコピーするわけではありません。
この仕組みは「Copy on Write(COW)」と呼ばれ、PHPのメモリチューニングの基本概念の一つです。
本記事では、COWの挙動をコード例とメモリ確認で解説し、上級試験で押さえておきたいポイントをまとめます。
コード例と実行結果
<?php
declare(strict_types=1);
error_reporting(-1);
function hoge($arg){
echo 'in hoge memory_get_usage: ', memory_get_usage(true), "\n";
}
echo 'start memory_get_usage: ', memory_get_usage(true), "\n";
$s = str_repeat('a',1_000_000);
echo '1st memory_get_usage: ', memory_get_usage(true), "\n";
$ss = $s;
echo '2st memory_get_usage: ', memory_get_usage(true), "\n";
hoge($s);
正しい出力例(環境によって多少差があります)
start memory_get_usage: 2097152
1st memory_get_usage: 12099584
2st memory_get_usage: 12099584
in hoge memory_get_usage: 12099584
挙動の解説
$s = str_repeat('a', 1_000_000);
→ 文字列データを生成し、メモリに確保。$ss = $s;
→ データはコピーされず、同じメモリ上の文字列を参照。
→ この時点ではメモリ使用量は増えない。hoge($s)
→ 関数に渡す際もコピーは行われず、同じデータを参照。
→ 変更がなければメモリ使用量は変わらない。- Write(書き込み)が発生した場合に初めてコピーされる
→ COW(Copy on Write)の本質。
ASCII図解:Copy on Write
代入直後(Copy on Write 前)
┌────────────────────┐
│ 実データ "aaaa..." │ ← 1MB
└────────────────────┘
▲ ▲ ▲
│ │ │
$s $ss hoge($s)
(参照カウント3)
いずれも同じデータを指している!
書き換えが発生した瞬間にコピー
$ss[0] = 'b'; ← ここで新しいメモリ確保
上級試験で押さえておくポイント
- 代入や引数渡しでメモリは増えない
- 変更(Write)時に初めてコピーされる
- memory_get_usage() で確認しても、COWにより増えないことがある
- Copy on Write は大きな配列や文字列を扱う際のメモリ節約の基本