1 前言html
昨天使用清華的源下載了android 6.0的源碼,校園網能夠達到10M的速度,爽!今天一大早就火燒眉毛地準備編譯一個模擬器版本,看看效果,哪知居然耗費了一成天的時間才搞定...爲了不其餘人在一樣的問題上浪費時間,特記錄整個編譯過程當中遇到的問題和解決方案,畢竟時間就是金錢!java
2 背景linux
我是在MAC上安裝的ubuntu14.04 64bit系統,起初分配了3G的內存(血的教訓,徹底不夠用!),和兩個核心。編譯的系統版本爲6.0.1_r9和6.0.0_r26android
3 編譯過程遇到的問題和解決方案git
整個編譯過程嚴格按照官網的說明進行,不過由於不須要常常編譯源碼,同時爲了節省空間,因此沒有使用ccache.ubuntu
起初編譯很順利,可是當執行到編譯java代碼(jar或者dex)階段的時候出現以下錯誤:工具
圖3.1 編譯錯誤反饋信息 oop
顯然,是一個叫作Jack的服務沒能啓動,那麼這個Jack是幹什麼的呢?截取官網信息簡要歸納以下:ui
Jack (Java Android Compiler Kit)是一個新的Android編譯工具,用於將Java代碼編譯爲Android dex字節碼,主要用於替換以前的編譯工具: javac, ProGuard, jarjar以及dx等等。更詳細的信息可參考官網介紹:google
https://source.android.com/source/jack.html#jack_intermediate_library_linker_jill
Jack的重要性不言而喻,所以若是不能正常啓動它的話,咱們的源碼是斷然沒法編譯下去的。那麼它爲何沒法啓動呢?
查看官網,有以下兩條提示信息:
If your computer becomes unresponsive during compilation or if you experience Jack compilations failing on 「Out of memory error」 You can improve the situation by reducing the number of Jack simultaneous compilations by editing your $HOME/.jack and changing SERVER_NB_COMPILE to a lower value. If your compilations are failing on 「Cannot launch background server」 The most likely cause is TCP ports are already used on your computer. Try to change it by editing your $HOME/.jack (SERVER_PORT_SERVICE and SERVER_PORT_ADMIN variables).
排除第二種狀況後,以爲第一種狀況頗有可能,由於從jack的啓動參數來看的話(從圖3.1編譯錯誤反饋信息能夠看出),在啓動jack的時候爲java虛擬機分配了2560M的內存,但我整個ubuntu虛擬機才3G啊!因此我立刻將Ubuntu虛擬機的內存增長到4G,而後從新編譯,不過我並無make clean由於前面非java部分的編譯都是沒問題的,而java部分編譯一開始就出錯了,因此不須要進行完全地從新編譯。
哪知,悲劇再次上演!當時兩眼抓瞎,都準備放棄了....中途去請教了下以前有過成功編譯經驗的同窗,覺得是版本的問題,因此將6.0.1_r9切換到6.0.0_r26後徹底從新編譯,漫長等待後也是出現一樣的問題。這裏記錄下切換源碼版本的方法:
① 首先進入源碼根目錄,將非.repo/ 文件所有刪掉。 ② 查看可切換的分支 cd .repo/manifests git branch -a | cut -d / -f 3 這裏選擇6.0.0_r26便可 ③ 切換分支 repo init -b android-6.0.0.0_r26 ④ 同步分支 repo sync 注:由於我以前同步的是6.0.1_r9的源碼,因此這一步很快就完成了,根據git的原理,並不須要從新下載整個源碼,因此這裏很快就完成了。
顯然,這根系統版本並沒太大關係,繼續分析Jack沒法啓動的緣由。偶然發現每次編譯失敗以後都會在源碼根目錄生成以下日誌文件:
從名字就能夠看出是一些錯誤日誌,打開看一看,關鍵信息截取以下:
1 # 2 # There is insufficient memory for the Java Runtime Environment to continue. 3 # Native memory allocation (malloc) failed to allocate 1789919232 bytes for committing reserved memory. 4 # Possible reasons: 5 # The system is out of physical RAM or swap space 6 # In 32 bit mode, the process size limit was hit 7 # Possible solutions: 8 # Reduce memory load on the system 9 # Increase physical memory or swap space 10 # Check if swap backing store is full 11 # Use 64 bit Java on a 64 bit OS 12 # Decrease Java heap size (-Xmx/-Xms) 13 # Decrease number of Java threads 14 # Decrease Java thread stack sizes (-Xss) 15 # Set larger code cache with -XX:ReservedCodeCacheSize= 16 # This output file may be truncated or incomplete. 17 # 18 # Out of Memory Error (os_linux.cpp:2827), pid=101129, tid=47875161523968 19 # 20 # JRE version: (7.0_91-b02) (build ) 21 # Java VM: OpenJDK 64-Bit Server VM (24.91-b01 mixed mode linux-amd64 compressed oops) 22 # Derivative: IcedTea 2.6.3 23 # Distribution: Ubuntu 14.04 LTS, package 7u91-2.6.3-0ubuntu0.14.04.1 24 # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again 25 #
從紅色加粗的信息能夠獲得以下結論:在爲Java虛擬機分配內存的時候失敗了,緣由就是內存不夠用。但按照個人經驗來看的話,4G內存不管怎樣都夠用了,那爲何仍是報錯呢?再仔細觀察一下錯誤日誌,裏面還說起了「swap空間問題」。問題可能出在它身上!swap分區主要用於在物理內存不夠用的狀況下,使用硬盤來模擬擴展物理內存,只是速度要慢幾個數量級而已。
我不記得當初安裝系統的時候是否分配了swap分區,因此使用以下命令查看:
chouchou:~$ sudo swapon -s [sudo] password for chouchou: Filename Type Size Used Priority
信息居然爲空!也就是說我並無swap分區,下面就開始建立分區了,這裏爲了方即可以使用swap文件的方式來實現:
建立4G大小的swapfile sudo fallocate -l 4G /swapfile 設置/swapfile權限 sudo chmod 600 /swapfile 設置swapfile sudo mkswap /swapfile 啓用 sudo swapon /swapfile 查看 sudo swapon -s [sudo] password for chouchou: Filename Type Size Used Priority /swapfile file 4194300 345156 -1
注意:這種方式建立的swap分區只是當前登陸狀態有效,重啓後就無效了。至於如何實現永久有效,你們可自行google。
如今再次編譯,一次性經過!上圖:
4 總結
此次編譯源碼花了一成天的時間,除了遇到Jack錯誤以外,在虛擬機裏面編譯源碼效率低下也是一個重要的因素。由於隨着Android系統的升級,源碼愈來愈龐大,其所須要的編譯環境也跟着水漲船高,所以有條件的最好仍是使用實體機編譯,且內存必定得大於4G!另外,遇到問題,第一時間查看錯誤日誌也很關鍵,這樣每每能在搜索不到解決方案的時候,快速定位問題,節約不少時間!