FreeBSD 9 - Adding Swap Space

先日,Wt C++ Web Toolkit Ver. 3.3.3 のコンパイルにおいて,gcc 4.2.1 を用いたところ,“Internal error” が出て失敗した件について書いた(「Clang/LLVM 3.3 の導入」)。問題のエラーは次のようなものである。

[ 66%] Building CXX object src/CMakeFiles/wt.dir/Wt/Render/CssParser.o
CC: Internal error: Killed: 9 (program cc1plus)
Please submit a full bug report.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
gmake[2]: *** [src/CMakeFiles/wt.dir/Wt/Render/CssParser.o] エラー 1
gmake[1]: *** [src/CMakeFiles/wt.dir/all] エラー 2
gmake: *** [all] エラー 2

しかしながら,Wt C++ Web Toolkit のインストールガイドには,“gcc-4.1.x or higher” というコンパイラ条件が明記されており,gcc 4.2.1 なら何の問題もないはずである。Clang/LLVM コンパイラにより導入はうまくいったわけだが,原因がはっきりせず,なんか気持ち悪い。今日,もういちど調べてみた。

問題の src/CMakeFiles/wt.dir/Wt/Render/CssParser.C を,gmake によらず自分でコマンドラインから g++ コマンドを投入してコンパイルしてみると,やはり Internal error が再現した。しかし,途中の経過メッセージには特段ヘンなものが出ているわけではなく,突然死のような終わり方だった。と,ふっと思いついてシスログをみたら,こんなのが出ていた。

Feb 23 19:04:30 beatrice kernel: pid 70751 (cc1plus), uid 1001, was killed: 
out of swap space

なんと,スワップエリア不足のために cc1plus (gcc C++ コンパイラの本体) を FreeBSD カーネルが kill したって次第である。「マジかよ」ってんで,swapinfo コマンドで swap エリアを確認したら,ない。df コマンドでも sw 属性のファイルシステムが見えない。スワップエリアとは(釈迦に説法かも知れないが),実メモリが不足する事態になったらここに仮想メモリイメージを退避し,必要に応じて実メモリとの間でページ(単位記憶域)を入れ替えながら,実メモリ容量以上の記憶域を運用する仕組みである。どうも,FreeBSD 9.2-RELEASE をインストールしたとき,私は swap エリアを切り忘れていたらしい。なんとも愚かな初歩的ミスである。これでよくもまあ動いていたもんだ。

# swapinfo
Device          1K-blocks     Used    Avail Capacity
# df -k
Filesystem   1024-blocks      Used     Avail Capacity  Mounted on
/dev/ada0s1a    10143484    304588   9027420     3%    /
devfs                  1         1         0   100%    /dev
/dev/ada0s1g   101554150  27424406  66005412    29%    /home
/dev/ada0s1h   623074770 459217250 114011540    80%    /shared
/dev/ada0s1b    50778204    200116  46515832     0%    /tmp
/dev/ada0s1d   101556508  18825556  74606432    20%    /usr
/dev/ada0s1e    50778204  11353276  35362672    24%    /var
fdescfs                1         1         0   100%    /dev/fd
procfs                 4         4         0   100%    /proc
/dev/md0           35228     16200     16212    50%    /usr/local/etc/misima

sysinstall コマンドでディスク・ラベルを確認すると,8GB 程度エリアが余っており,もともとこの余りエリアを swap パーティションにするつもりだったらしいことは推察できたが,それを忘れ,swap が追加されていないのは明らかだった。余りエリアに swap パーティションを作成するか…。いや,これはリスクが高い(ヘタするとデータすべてがふっとんでしまう)ので,急場凌ぎとして,ファイルシステム上に swap スペースを追加することにした。

FreeBSD Handbook - Adding Swap Space の記述に従って,作業することに。/var の下に swap0 という名の swap スペースを追加した。オペレーションは以下の通り。[ ] 内に若干のオペレーション説明を入れてある。これは FreeBSD 9 でのオペレーションであって,FreeBSD 10 の場合は作業内容が異なるので注意が必要である。必ず Handbook を確認していただきたい。

[ 8GB = 1MB * 8192 の容量の /var/swap0 を作成する ]
# dd if=/dev/zero of=/var/swap0 bs=1m count=8192
[ 所有者 root のみ読み書き可能にする ]
# chmod 0600 /var/swap0
# ls -als /var/swap0
-rw-------  1 root  wheel  8589934592  2月 23 19:10 /var/swap0
[ /etc/rc.conf に swapfile を指示する記述を追加 (vi で追加,grep で確認) ]
# vi /etc/rc.conf
# grep -e 'swapfile' /etc/rc.conf
swapfile="/var/swap0"
[ メモリディスクとして swap0 を生成する。md0 は使用中なので md1 を指示 (-u 1) ]
# mdconfig -a -t vnode -f /var/swap0 -u 1
[ swap エリアを有効にする ]
# swapon /dev/md1
[ システムに認識されているか確認する ]
# swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/md1          8388608       88  8388520     0%

これで swap スペースが 8GB 使えるようになった。Wt コンパイルをしてみたら,きちんと通った。top コマンドでメモリの使用状況をウォッチングしてみたが,問題の CssParser.C のコンパイルで cc1plus が 1GB 近くメモリを使い,わずかながらページアウトしている様子が確認できた(下図参照)。これまでは swap エリアがないため,ページアウト要求が出た瞬間に停止してしまったわけである。Clang/LLVM は gcc に比べ,メモリ消費量が少なかったためか,たまたまうまくいったということ。

20150223-top.png
top コマンド(“512K Out”が出ている)

これでスッキリ。問題が起きたとき,端末出力だけでなく,シスログくらいはすぐに確認すべきなんである。これが今回の教訓。