MacBook Airの内蔵SSDのストレージ領域を表示した時、使用済み容量の値がストレージ容量の値を超過していることもあるという。実際に見せてもらったことがあるのは「使用済み 1.02TB / 994.66GB
」という値だ。ちなみに、ストレージ領域の詳細と棒グラフは、macOSの左上のりんごマーク > システム設定 > 一般 > ストレージ と辿れば確認できる。
使用済み容量が超過するなんて、そんな奇天烈な使用状況を生じさせている原因は何だろう?と私は興味を持った。iCloud Driveが介入しているわけでもなさそうだし、macOSにおいて、ファイルの「透過的圧縮」が行われるとは聞かないし、NetAppストレージのような「重複排除」の話も聞かない。そこでウェブ情報を色々調べてみたところ、macOSの標準ファイルシステム Apple File System (APFS) にはクローンという機能が備わっていることを知り、この機能をよく使っている環境ほど、容量超過の表示は起こりうるのでは?と、仮説を立てた。ならば実験してみよう。
Apple File System (APFS) について、詳しくは次のページを参照。ストレージの利用効率を高める「クローン」についての記述もある。
クローンの効果を単純化した例で考えてみる。APFSの上で、例えばサイズが100MBの既存のファイルを複製し、新たに9個のファイルを作る場合。このときの複製動作が実際のところクローン動作であれば、クローンは追加容量を必要としないので、10個のファイルの物理的な、実際の使用容量は合計でも (ほぼ) 100MBのはずだ。一方、論理的には100MBのファイルが10個に増えたのだからデータ量は合計で1,000MBになる。
今回の実験ではクローン機能を活用して、明らかな「使用済み」の容量>ストレージ容量
な状況を作り出すことが目標だ。具体的な方法としては、対象ストレージに保存可能でかつできるだけ大きい数百GBサイズの実体ファイルを最初に用意し、それをcp -c
(-c
はクローンファイルとしてコピーする、macOS独自と思われるオプション) で自動的に大量作成するスクリプトを実行する。
ちなみに、神戸ポートアイランドにあるスーパーコンピュータ「富岳」のストレージ容量は、第2階層の共有ファイルシステムの領域で「150PB」なのだそうだ。私はミーハーなので、この富岳よりも大きい値を、ストレージ容量が1TBのMacBook Airのストレージ使用状況に表示させることができたらば実験は成功とする。
test_clonefile.sh
というbashスクリプト (下記参照) を作成し、このスクリプトをストレージ容量1TBのMacBook Air (M1, 2020) のmacOS Ventura 13.6環境で実行したところ、実験終了時には「222.71PB」という奇天烈な、使用済み容量の表示を実現できた。ちなみにスクリプト実行の所要時間は63分38秒。もしかしたら5倍の時間をかけたら、1,024PBを超えたEB (エクサバイト) の世界がMacBook Airの上で垣間見れたのかもしれない。
容量 (使用済み/ストレージ容量) | 使用済み容量 | |
---|---|---|
実験開始時 | 262.29GB / 994.66GB | ←これを1 (基準) とすると |
実験終了時 | 222.71PB / 994.66GB | ←見かけ上は約91万倍 |
SanDisk SSD 外付け 8TB USB 3.2 Gen 2x1 読出最大1000MB/秒 サンディスク Desk Drive SSD SDSSDT40-8T00-NA25 メーカー保証3年
SanDisk
このbashスクリプトtest_clonefile.sh
は、ランダムデータが埋め込まれたサイズ200GBのファイルを実際に作り、そのファイルのクローンを1,048,576個作成する。ストレージ上の実際の使用容量は約200GBに留まるものの、約100万個という大量のファイルをファイルシステム上に作成することには違いなく、それなりにSSDを痛めつける可能性がある。もし試してみる場合にはストレージ障害に十分ご注意ください。
#!/usr/bin/env bash
set -euox pipefail
# test_clonefile.sh (Ver.20240601) for macOS APFS
# clonefileでの見かけ上と実際の容量消費を確認するスクリプト
DIR_TMP='./tmp_cloneworld'
FILE_ORIGIN=realfile.tmp
FILE_SIZE_UNIT=1024M
FILE_SIZE_COUNT=200 # -> 1024MB*200 = 200GB per file
#COPY_REPEAT=1024 # -> 200GB*1024 = 200TB
COPY_REPEAT=1048576 # -> 200GB*1024*1024 = 200TB*1024 = 200PB
# 使用する容量を表示
echo "実体ファイルの消費容量: ${FILE_SIZE_COUNT} * ${FILE_SIZE_UNIT} bytes"
TMP_SIZE=$(expr ${FILE_SIZE_COUNT} \* ${COPY_REPEAT})
echo "clonefileの消費容量: ${TMP_SIZE} * ${FILE_SIZE_UNIT} bytes"
# 作業ディレクトリDIR_TMPを作成
mkdir -p ${DIR_TMP}
# 実体ファイルFILE_ORIGINを作成
dd if=/dev/urandom bs=${FILE_SIZE_UNIT} count=${FILE_SIZE_COUNT} of=${DIR_TMP}/${FILE_ORIGIN}
# 実体ファイルを指定回数、clonefileとして複製する
for i in $(seq -f "%.0f" 1 ${COPY_REPEAT}); do
j=$(printf "%08d" ${i})
FILE_COPY=clonefile_${j}.tmp
cp -c ${DIR_TMP}/${FILE_ORIGIN} ${DIR_TMP}/${FILE_COPY}
done
# ストレージの使用量を表示
echo '# df -h'
df -h ${DIR_TMP}
# 作業ディレクトリDIR_TMPの使用容量を表示
echo '# du -sh'
du -sh ${DIR_TMP}
# 終了メッセージ
echo 'DIR_TMPの削除には時間がかかります。次のコマンドで手動で行ってください。'
echo "rm -rf -v ${DIR_TMP}/"