Androidのビルドでメモリが不足しているときのvmstat
RAMを1GBしか割り当ててないVMWareの仮想マシンで、無謀にもAOSPのmasterのAndroidをビルドしてみました。
$ nohup make > make.log 2>&1 & $ tail -F make.log
一晩かかる覚悟なので、ログアウトしても続行するように nohup をつけてバックグランドで実行しています。メモリが少ないので -j で並列化はしません。
tail -F でログをのぞいてみると
... aapt: warning: string 'gsm_alphabet_default_charset' has no default translation in frameworks/base/core/res/res; found: ko target Java: framework (out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes) Note: Some input files use or override a deprecated API. Note: Recompile with -Xlint:deprecation for details. Note: Some input files use unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. Copying: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-jarjar.jar Copying: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/emma_out/lib/classes-jarjar.jar Copying: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar Copying: out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/noproguard.classes.jar target Dex: framework
この状態のままずっと止まっています。
別のTerminalから top コマンドで見てみると
top - 23:25:22 up 12:05, 4 users, load average: 2.13, 2.16, 1.99 Tasks: 79 total, 1 running, 78 sleeping, 0 stopped, 0 zombie Cpu(s): 0.3%us, 7.2%sy, 0.0%ni, 0.0%id, 92.1%wa, 0.0%hi, 0.3%si, 0.0%st Mem: 1019500k total, 960320k used, 59180k free, 72k buffers Swap: 1044476k total, 719960k used, 324516k free, 1712k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3418 koba 20 0 2136m 877m 4 S 6.2 88.1 3:00.08 java 22 root 20 0 0 0 0 D 1.6 0.0 1:36.27 kswapd0 3 root 20 0 0 0 0 S 0.3 0.0 0:19.09 ksoftirqd/0 3682 root 20 0 0 0 0 S 0.3 0.0 0:00.02 kworker/0:2 1 root 20 0 24328 4 4 S 0.0 0.0 0:02.10 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 5 root 20 0 0 0 0 S 0.0 0.0 0:36.78 kworker/u:0 6 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 7 root RT 0 0 0 0 S 0.0 0.0 1:01.59 watchdog/0 8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset 9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper 10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs 11 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 netns 12 root 20 0 0 0 0 S 0.0 0.0 0:01.60 sync_supers 13 root 20 0 0 0 0 S 0.0 0.0 0:00.30 bdi-default 14 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kintegrityd 15 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kblockd
たしかにjavaコマンドが大量にメモリを食っています。でも忙しいはずなのにCPUは6.2%しか使っていません、
vmstat コマンドで仮想メモリの様子をみてみると
$ vmstat 5
これで5秒ごとに状態が表示されます。
... procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 1 6 725912 57464 80 7912 3123 591 3126 602 699 637 2 8 0 89 1 6 721608 49188 88 8336 3460 450 3549 456 766 827 8 10 0 82 0 3 721104 54832 96 8940 2667 614 2787 624 687 581 3 10 0 87 0 2 722540 55432 1156 10936 2743 1021 3470 1026 705 609 1 8 0 91 0 3 725296 68844 64 4112 3341 1455 3558 1478 857 686 1 10 0 90 1 2 723764 54972 72 7856 2758 469 4718 471 675 520 1 5 0 94 0 2 721944 57576 72 8832 3386 918 3606 922 822 801 1 10 0 89 2 2 720836 59188 68 8836 3029 730 3038 736 744 640 1 9 0 89 0 4 720900 58932 68 9124 3529 925 3586 927 799 694 1 9 0 90 0 2 722444 50260 76 9088 3328 1191 3328 1194 806 704 0 6 0 93 1 2 725964 59808 84 9100 2990 1523 2990 1533 808 665 1 7 0 92 0 4 728740 50500 88 9124 3094 1376 3094 1378 755 547 1 5 0 94 2 1 727372 67496 80 3292 2911 634 2911 640 719 511 1 8 0 91 0 2 726128 52740 84 3308 3885 830 3885 833 888 676 1 6 0 93 0 1 724024 64136 64 3784 3473 601 3738 604 858 739 1 8 0 91 0 2 727064 56332 72 4480 3561 1790 3561 1793 809 724 1 6 0 93 0 3 729900 71428 64 3272 3166 1695 3390 1701 823 712 1 9 0 91 0 1 730292 62392 72 2092 3925 1518 4637 1521 909 814 1 7 0 93
si, so に注目。メモリが足りないので、swapに掃き出しと読み込みが激しく行われています。
cpuは90%以上がI/O待ち状態です。(一番右のwaの項目) これではcpuがいくら速くても意味がありません。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 3418 koba 20 0 2136m 877m 4 S 6.2 88.1 3:00.08 java
topの画面をよく見ると、このjavaのプロセスは2136MBの仮想メモリを要求していて、割り当てられた物理メモリが877MB。実際に1024MBしかRAMは無いのでこれで全く足りず、swapという借金に手を出さざるをえない状態です。
ウィキペディアの「スラッシング」に書いてあるそのものずばりのケースです。
「物理メモリが1GBしかないのに2GBのメモリを使うアプリケーションを動かした等の場合」
スラッシング - Wikipedia
あまりにひどいので、いったん仮想マシンを止めて、RAMを2048MBに増やしてやり直しました。今度はcpuの利用率が90%以上に上がって進行するようになりました。
Androidのビルドには最低2GBのRAMは必要だとわかりました。しかし2GBでは一晩かかります。
メモリが十分にあってcpuが休み無く働いている状態は以下のページを見てください。
Androidをビルドしているときのvmstat - 組み込みの人。