Go 1.7 讓二進制文件變得更小
引言
Go語言是為編寫服務端軟件而設計的,這也是為什么今天它被廣泛使用的原因。因此大量的在運行時和編譯器的優化工作都集中在與服務端軟件相關的問題:延時、易于部署、精確的垃圾回收、啟動快速以及性能。
因為Go大量使用于不同類型的程序,因此必須考慮一些新的問題。其中之一是二進制文件的大小。雖然這個問題已經被發現很久了(issue #6853在兩年前被提出),但是隨著人們越來越多的在小型設備(比如樹莓派或者移動設備)上部署Go的二進制文件,意味著Go1.7的發布能收到更多的關注。
在Go 1.7中的工作
Go1.7中的三個重大的改變影響了二進制文件的大小。
第一個是在這個版本針對AMD64啟用了新的SSA后端。雖然引入SSA的主要動機是為了改善性能,但是產生的代碼體積也小了。SSA后端把Go的二進制文件體積壓縮大約5%。我們期望在Go1.8版本發布時,ARM和MIPS這些RISC架構的后端換為SSA,能帶來更大的收益。
第二個改變是函數裁剪。直到1.6版本,雖然有些方法從未被調用,但是在所有使用的類型的所有的方法都被保留了。這是因為他們可能通過接口被調用或者使用反射包被動態地調用。現在編譯器丟棄了那些不匹配接口的所有未導出的方法。類似地,如果相應的反射特性沒有在程序中被用到,鏈接器可以丟棄其他未導出方法,這些方法只有通過反射才能獲取到。這個改變可以把二進制文件的體積壓縮5-20%。
第三個改變是反射包使用的運行時類型信息采用了更加緊湊的格式。編碼格式最初被設計為使得運行時和反射包的譯碼器盡可能地簡單。通過使得這些代碼稍微難以閱讀,在不影響Go程序的運行時性能的前提下,我們壓縮了格式。新的格式把Go二進制文件的體積進一步壓縮了5-15%。為Android編譯的動態庫和為iOS歸檔文件進一步壓縮,因為新的格式包含更少的指針,而這些指針在位置獨立的代碼處需要動態重映射。
另外,還有很多小改進,比如改良的接口數據布局,更好的靜態數據布局以及簡化的依賴。比如,HTTP client不再在整個HTTP server鏈接。改變的完整修改列表可以在issue #6953得到。
結果 當使用了Go 1.7,典型的程序(從小玩具到大型生產項目)的體積大約減小了30%。
規范的hello world程序的體積從2.3MB減小到1.6MB。
package mainimport "fmt"
func main() { fmt.Println("Hello, World!") }</pre>
如果編譯時沒有調試信息,現在靜態鏈接的二進制文件小于1MB。
測試這個特性,我采用了一個更大的生產環境程序,jujud,其體積從94MB減小為67MB。
地址無關 的二進制文件可以減小50%。 在 地址無關 的可執行程序(PIE)中,在只讀數據段的指針需要動態重映射。因為新的類型信息格式通過段偏移單元代替了了指針,這樣,每個指針節省了28個字節。
移除調試信息的 地址無關 的可執行程序對于移動開發者很重要,因為這是發布到手機端的程序。因為下載大體積的應用程序的用戶體驗差,所以體積減少對他們來說是個好消息。
未來的工作
一些運行時類型信息的改變沒有趕上Go1.7版本凍結,但是希望會在1.8版本加入。這些會進一步減小程序體積,尤其是對 地址無關 的程序。
這些改變都是保守的,減小二進制文件的體積不會增加編譯時間、啟動時間、整體的運行時間以及內存使用量。我們會進行更徹底的做法來減小二進制文件的體積:upx工具可以把二進制文件的體積進一步壓縮50%,代價是增加啟動時間和潛在的內存使用量。針對非常小的系統(可能在鑰匙掛上),我們會編譯一個沒有反射的Go,雖然還不確定這樣一個有限制的語言是否是非常有用。在運行時中,當計算每個kb字節時,我們會使用稍微慢點但是更緊湊的算法。所有的這些需要在后續的開發周期中做更多的調研。
來自:http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369749&idx=1&sn=e52cd2766404f27bf47cb95ef22c00f0&scene=1&srcid=0822m02c3Uj65Sazdgw1FG4A&from=groupmessage&isappinstalled=0