先日,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 に比べ,メモリ消費量が少なかったためか,たまたまうまくいったということ。
top コマンド(“512K Out”が出ている)
これでスッキリ。問題が起きたとき,端末出力だけでなく,シスログくらいはすぐに確認すべきなんである。これが今回の教訓。