日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Go未用代碼消除與可執行文件瘦身

來源: 責編: 時間:2024-05-07 09:14:52 235觀看
導讀在日常編寫Go代碼時,我們會編寫很多包,也會在編寫的包中引入了各種依賴包。在大型Go工程中,這些直接依賴和間接依賴的包數目可能會有幾十個甚至上百個。依賴包有大有小,但通常我們不會使用到依賴包中的所有導出函數或類型

在日常編寫Go代碼時,我們會編寫很多包,也會在編寫的包中引入了各種依賴包。在大型Go工程中,這些直接依賴和間接依賴的包數目可能會有幾十個甚至上百個。依賴包有大有小,但通常我們不會使用到依賴包中的所有導出函數或類型方法。KL928資訊網——每日最新資訊28at.com

這時Go初學者就會有一個疑問:這些直接依賴包和間接依賴包中的所有代碼是否會進入到最終的可執行文件中呢?即便我們只是使用了某個依賴包中的一個導出函數。KL928資訊網——每日最新資訊28at.com

這里先給出結論:不會!在這篇文章中,我們就來探索一下這個話題,了解一下其背后的支撐機制以及對Go可執行文件Size的影響。KL928資訊網——每日最新資訊28at.com

1. 實驗:哪些函數進入到最終的可執行文件中了?

我們先來做個實驗,驗證一下究竟哪些函數進入到最終的可執行文件中了!我們建立demo1,其目錄結構和部分代碼如下:KL928資訊網——每日最新資訊28at.com

// dead-code-elimination/demo1 $tree -F ..├── go.mod├── main.go└── pkga/    └── pkga.go// main.gopackage main  import (    "fmt"    "demo/pkga")func main() {    result := pkga.Foo()    fmt.Println(result)}// pkga/pkga.gopackage pkgaimport ( "fmt")func Foo() string { return "Hello from Foo!"}func Bar() { fmt.Println("This is Bar.")}

這個示例十分簡單!main函數中調用了pkga包的導出函數Foo,而pkga包中除了Foo函數,還有Bar函數(但并沒有被任何其他函數調用)。現在我們來編譯一下這個module,然后查看一下編譯出的可執行文件中都包含pkga包的哪些函數!(本文實驗中使用的Go為1.22.0版本[1])KL928資訊網——每日最新資訊28at.com

$go build$go tool nm demo|grep demo

在輸出的可執行文件中,居然沒有查到關于pkga的任何符號信息,這可能是Go的優化在“作祟”。我們關閉掉Go編譯器的優化后,再來試試:KL928資訊網——每日最新資訊28at.com

$go build -gcflags '-l -N'$go tool nm demo|grep demo 108ca80 T demo/pkga.Foo

關掉內聯優化[2]后,我們看到pkga.Foo出現在最終的可執行文件demo中,但并未被調用的Bar函數并沒有進入可執行文件demo中。KL928資訊網——每日最新資訊28at.com

我們再來看一下有間接依賴的例子:KL928資訊網——每日最新資訊28at.com

// dead-code-elimination/demo2$tree ..├── go.mod├── main.go├── pkga│   └── pkga.go└── pkgb    └── pkgb.go// pkga/pkga.gopackage pkgaimport ( "demo/pkgb" "fmt")func Foo() string { pkgb.Zoo() return "Hello from Foo!"}func Bar() { fmt.Println("This is Bar.")}

在這個示例中,我們在pkga.Foo函數中又調用了一個新包pkgb的Zoo函數,我們來編譯一下該新示例并查看一下哪些函數進入到最終的可執行文件中:KL928資訊網——每日最新資訊28at.com

$go build -gcflags='-l -N'$go tool nm demo|grep demo 1093b40 T demo/pkga.Foo 1093aa0 T demo/pkgb.Zoo

我們看到:只有程序執行路徑上能夠觸達(被調用)的函數才會進入到最終的可執行文件中!KL928資訊網——每日最新資訊28at.com

在復雜的示例中,我們也可以通過帶有-ldflags='-dumpdep'的go build命令來查看這種調用依賴關系(這里以demo2為例):KL928資訊網——每日最新資訊28at.com

$go build -ldflags='-dumpdep' -gcflags='-l -N' > deps.txt 2>&1$grep demo deps.txt# demomain.main -> demo/pkga.Foodemo/pkga.Foo -> demo/pkgb.Zoodemo/pkga.Foo -> go:string."Hello from Foo!"demo/pkgb.Zoo -> math/rand.Int31ndemo/pkgb.Zoo -> demo/pkgb..stmp_0demo/pkgb..stmp_0 -> go:string."Zoo in pkgb"

到這里,我們知道了Go通過某種機制保證了只有真正使用到的代碼才會最終進入到可執行文件中,即便某些代碼(比如pkga.Bar)和那些被真正使用的代碼(比如pkga.Foo)在同一個包內。這同時保證了最終可執行文件大小在可控范圍內。KL928資訊網——每日最新資訊28at.com

接下來,我們就來看看Go的這種機制。KL928資訊網——每日最新資訊28at.com

2. 未用代碼消除(dead code elimination)

我們先來復習一下go build的構建過程,以下是 go build 命令的步驟概述:KL928資訊網——每日最新資訊28at.com

  1. 讀取go.mod和go.sum:如果當前目錄包含go.mod文件,go build會讀取該文件以確定項目的依賴項。它還會根據go.sum文件中的校驗和驗證依賴項的完整性。
  2. 計算包依賴圖:go build 分析正在構建的包及其依賴項中的導入語句,以構建依賴圖。該圖表示包之間的關系,使編譯器能夠確定包的構建順序。
  3. 決定要構建的包:基于構建緩存和依賴圖,go build 確定需要構建的包。它檢查構建緩存,以查看已編譯的包是否是最新的。如果自上次構建以來某個包或其依賴項發生了更改,go build將重新構建這些包。
  4. 調用編譯器(go tool compile):對于每個需要構建的包,go build調用Go編譯器(go tool compile)。編譯器將Go源代碼轉換為特定目標平臺的機器碼,并生成目標文件(.o 文件)。
  5. 調用鏈接器(go tool link):在編譯所有必要的包之后,go build 調用 Go 鏈接器(go tool link)。鏈接器將編譯器生成的目標文件合并為可執行二進制文件或包歸檔文件。它解析包之間的符號和引用,執行必要的重定位,并生成最終的輸出。

上述的整個構建過程可以由下圖表示:KL928資訊網——每日最新資訊28at.com

圖片圖片KL928資訊網——每日最新資訊28at.com

在構建過程中,go build 命令還執行各種優化,例如未用代碼消除和內聯,以提高生成二進制文件的性能和降低二進制文件的大小。其中的未用代碼消除就是保證Go生成的二進制文件大小可控的重要機制。KL928資訊網——每日最新資訊28at.com

未用檢測算法的實現位于 $GOROOT/src/cmd/link/internal/ld/deadcode.go文件中。該算法通過圖遍歷的方式進行,具體過程如下:KL928資訊網——每日最新資訊28at.com

  1. 從系統的入口點開始,標記所有可通過重定位到達的符號。重定位是兩個符號之間的依賴關系。
  2. 通過遍歷重定位關系,算法標記所有可以從入口點訪問到的符號。例如,在主函數main.main中調用了pkga.Foo函數,那么main.main會有對這個函數的重定位信息。
  3. 標記完成后,算法會將所有未被標記的符號標記為不可達的未用。這些未被標記的符號表示不會被入口點或其他可達符號訪問到的代碼。

不過,這里有一個特殊的語法元素要注意,那就是帶有方法的類型。類型的方法是否進入到最終的可執行文件中,需要考慮不同情況。在deadcode.go,用于標記可達符號的函數實現將可達類型的方法的調用方式分為三種:KL928資訊網——每日最新資訊28at.com

  1. 直接調用
  2. 通過可到達的接口類型調用
  3. 通過反射調用:reflect.Value.Method(或 MethodByName)或 reflect.Type.Method(或 MethodByName)

第一種情況,可以直接將調用的方法被標記為可到達。第二種情況通過將所有可到達的接口類型分解為方法簽名來處理。遇到的每個方法都與接口方法簽名進行比較,如果匹配,則將其標記為可到達。這種方法非常保守,但簡單且正確。KL928資訊網——每日最新資訊28at.com

第三種情況通過尋找編譯器標記為REFLECTMETHOD的函數來處理。函數F上的REFLECTMETHOD意味著F使用反射進行方法查找,但編譯器無法在靜態分析階段確定方法名。因此所有調用reflect.Value.Method 或reflect.Type.Method的函數都是REFLECTMETHOD。調用reflect.Value.MethodByName或reflect.Type.MethodByName且參數為非常量的函數也是REFLECTMETHOD。如果我們找到了REFLECTMETHOD,就會放棄靜態分析,并將所有可到達類型的導出方法標記為可達。KL928資訊網——每日最新資訊28at.com

下面是一個來自參考資料中的示例:KL928資訊網——每日最新資訊28at.com

// dead-code-elimination/demo3/main.gotype X struct{}type Y struct{}func (*X) One()   { fmt.Println("hello 1") }func (*X) Two()   { fmt.Println("hello 2") }func (*X) Three() { fmt.Println("hello 3") }func (*Y) Four()  { fmt.Println("hello 4") }func (*Y) Five()  { fmt.Println("hello 5") }func main() {    var name string    fmt.Scanf("%s", &name)    reflect.ValueOf(&X{}).MethodByName(name).Call(nil)    var y Y    y.Five()}

在這個示例中,類型*X有三個方法,類型*Y有兩個方法,在main函數中,我們通過反射調用X實例的方法,通過Y實例直接調用Y的方法,我們看看最終X和Y都有哪些方法進入到最后的可執行文件中了:KL928資訊網——每日最新資訊28at.com

$go build -gcflags='-l -N'$go tool nm ./demo|grep main 11d59c0 D go:main.inittasks 10d4500 T main.(*X).One 10d4640 T main.(*X).Three 10d45a0 T main.(*X).Two 10d46e0 T main.(*Y).Five 10d4780 T main.main... ...

我們看到通過直接調用的可達類型Y只有代碼中直接調用的方法Five進入到最終可執行文件中,而通過反射調用的X的所有方法都可以在最終可執行文件找到!這與前面提到的第三種情況一致。KL928資訊網——每日最新資訊28at.com

3. 小結

本文介紹了Go語言中的未用代碼消除和可執行文件瘦身機制。通過實驗驗證,只有在程序執行路徑上被調用的函數才會進入最終的可執行文件,未被調用的函數會被消除。KL928資訊網——每日最新資訊28at.com

本文解釋了Go編譯過程,包括包依賴圖計算、編譯和鏈接等步驟,并指出未用代碼消除是其中的重要優化策略。具體的未用代碼消除算法是通過圖遍歷實現的,標記可達的符號并將未被標記的符號視為未用。文章還提到了對類型方法的處理方式。KL928資訊網——每日最新資訊28at.com

通過這種未用代碼消除機制,Go語言能夠控制最終可執行文件的大小,實現可執行文件瘦身。KL928資訊網——每日最新資訊28at.com

本文涉及的源碼可以在這里[3]下載。KL928資訊網——每日最新資訊28at.com

4. 參考資料

  • Getting the most out of Dead Code elimination[4] - https://golab.io/talks/getting-the-most-out-of-dead-code-elimination
  • all: binaries too big and growing[5] - https://github.com/golang/go/issues/6853
  • aarzilli/whydeadcode[6] - https://github.com/aarzilli/whydeadcode

本文鏈接:http://m.www897cc.com/showinfo-26-87033-0.htmlGo未用代碼消除與可執行文件瘦身

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 15個適合后端程序員的前端框架

下一篇: 我使用緩存,踩過的7個坑

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
男女视频一区二区| 亚洲午夜极品| 韩日欧美一区二区| 有码中文亚洲精品| 亚洲欧洲日韩综合二区| 一二美女精品欧洲| 午夜亚洲一区| 久久久久久亚洲精品中文字幕| 久热这里只精品99re8久| 欧美高清在线视频| 国产精品vip| 国产偷自视频区视频一区二区| 激情综合视频| 99热这里只有精品8| 在线亚洲一区| 欧美自拍偷拍| 欧美激情1区2区| 国产精品久久网站| 影音先锋日韩精品| 中文高清一区| 久久人人九九| 国产精品草莓在线免费观看| 国产综合精品一区| 99精品99| 久久人人爽人人爽爽久久| 欧美日韩中文| 影音先锋一区| 亚洲欧美成人| 欧美成人按摩| 国产美女诱惑一区二区| 亚洲国产视频a| 欧美一级网站| 欧美日韩亚洲视频| 精品91视频| 亚洲女ⅴideoshd黑人| 欧美成人免费网站| 国产亚洲精品bt天堂精选| 日韩系列在线| 麻豆精品精品国产自在97香蕉| 国产精品国产三级国产| 亚洲国产色一区| 久久精品视频亚洲| 国产精品久久久久av免费| 亚洲激情偷拍| 久久视频国产精品免费视频在线| 国产精品成人观看视频国产奇米| 亚洲第一在线视频| 久久国产高清| 国产精品视频久久久| 亚洲精品色婷婷福利天堂| 久久久久久久999精品视频| 国产精品久线观看视频| 亚洲精品在线观看视频| 久久尤物视频| 国产色综合网| 午夜精品久久久久久久久久久久 | 久久久久久久综合色一本| 欧美无乱码久久久免费午夜一区| 亚洲国产99精品国自产| 久久久91精品国产| 国产美女精品| 亚洲欧美国产日韩天堂区| 欧美日韩午夜在线| 亚洲精品一区二区三区在线观看| 久久综合伊人77777麻豆| 国产一区二区三区高清在线观看| 亚洲欧美日韩国产另类专区| 国产精品jvid在线观看蜜臀| 99视频在线精品国自产拍免费观看| 欧美成人a∨高清免费观看| 极品少妇一区二区| 久久久www成人免费无遮挡大片| 国产欧美1区2区3区| 亚洲一区二区在线| 国产精品都在这里| 亚洲一区免费网站| 国产精品久久久久久久app| 一区二区三区精品国产| 欧美日本在线看| 99re国产精品| 欧美激情在线| 亚洲毛片在线观看| 欧美理论在线播放| 99这里只有精品| 欧美日韩国产在线观看| 99精品热视频| 欧美日韩中文字幕在线| 在线亚洲成人| 国产精品久久久久久福利一牛影视| 亚洲免费视频中文字幕| 国产老女人精品毛片久久| 欧美一区二区免费| 国产主播喷水一区二区| 久久久久久网址| 亚洲福利视频一区| 欧美精品99| 亚洲午夜羞羞片| 国产麻豆视频精品| 久久久不卡网国产精品一区| 黑人一区二区| 久热精品视频在线观看一区| 亚洲人成在线观看网站高清| 欧美日韩视频在线一区二区| 亚洲尤物精选| 国内精品99| 免费在线成人| 在线视频精品一区| 国产毛片精品视频| 久久久最新网址| 亚洲精品国产精品久久清纯直播| 欧美日韩小视频| 欧美一区二粉嫩精品国产一线天| 激情文学综合丁香| 欧美激情一区二区三区高清视频 | 国产揄拍国内精品对白| 久久亚洲二区| 亚洲毛片在线免费观看| 国产精品麻豆va在线播放| 久久成人人人人精品欧| 亚洲电影免费观看高清| 欧美日韩一区二区三区高清| 午夜精品影院在线观看| 在线电影国产精品| 欧美日韩国产精品一区| 性久久久久久久| 亚洲福利精品| 国产精品成人一区二区三区吃奶| 久久精品国产999大香线蕉| 最新69国产成人精品视频免费| 欧美亚洲成人精品| 久久久久九九视频| 一区二区三区高清在线| 极品av少妇一区二区| 欧美日韩免费观看一区三区| 欧美综合国产| 一区二区三区高清| 激情亚洲一区二区三区四区| 欧美日韩一卡| 久久免费高清| 一区二区三区四区国产| 韩日在线一区| 国产精品草莓在线免费观看| 乱中年女人伦av一区二区| 亚洲午夜精品久久| 亚洲第一在线视频| 国产精品欧美日韩| 欧美国产视频一区二区| 欧美一区二区三区免费观看视频| 亚洲欧洲另类| 国产亚洲日本欧美韩国| 欧美日韩精品在线| 久久午夜电影| 午夜久久福利| 日韩一二三区视频| 影音国产精品| 国产日本欧美一区二区| 欧美日韩日本国产亚洲在线| 久久久久.com| 亚洲欧美色一区| 99国产一区二区三精品乱码| 尤物九九久久国产精品的分类| 国产精品三级视频| 欧美精品三级在线观看| 久久男人资源视频| 性亚洲最疯狂xxxx高清| 一区二区三区黄色| 亚洲精品视频免费| 在线成人激情| 国产亚洲欧美一区二区| 国产精品成人观看视频免费| 欧美黑人多人双交| 久久久久综合一区二区三区| 亚洲欧美日韩高清| 一区二区三区四区在线| 亚洲肉体裸体xxxx137| 伊人成年综合电影网| 国产啪精品视频| 国产精品久久久久毛片大屁完整版| 欧美精品久久99| 欧美成人免费视频| 裸体一区二区三区| 久久久青草青青国产亚洲免观| 香蕉成人伊视频在线观看| 在线亚洲免费视频| 日韩午夜电影在线观看| 亚洲激情黄色| 亚洲国产91色在线| 亚洲第一伊人| 亚洲风情在线资源站| 亚洲第一精品夜夜躁人人躁| 狠狠久久亚洲欧美| 国产真实乱偷精品视频免| 国产日韩欧美日韩| 国产九色精品成人porny| 国产精品黄色| 国产精品久久波多野结衣| 欧美日韩直播| 国产精品久久久久久久7电影| 国产精品videossex久久发布| 欧美日韩中文精品| 欧美午夜电影完整版| 国产精品久久网站| 国产人久久人人人人爽| 国产欧美精品va在线观看|