主記憶體:配置、連結與分段

靜態連結與動態連結(static vs dynamic linking)

想像為一趟旅行打包。你可以把所有可能用到的工具全塞進自己的行李箱,這樣完全自給自足但很重(靜態),也可以輕裝出發、抵達後借用旅館的工具,與其他房客共用(動態)。靜態連結與動態連結對程式所依賴的程式庫程式碼就是同一個選擇:把自己的一份副本烙進可執行檔,或在啟動時取用一份共享副本。

靜態連結在建置時把所需的程式庫常式複製進可執行檔本身。結果是一個大而自足的檔案,執行時不需要其他東西;每個使用例如字串程式庫的程式都帶著自己私有的一份副本。動態連結則只在可執行檔裡留下一小段樁;真正的程式庫(共享程式庫:Linux 上是 .so 檔、Windows 上是 .dll)在啟動時被載入記憶體,並由載入器和動態連結器在那時接上。許多程式可以共用同一個程式庫在記憶體中的一份副本。這仰賴位置無關程式碼——撰寫成不論被載入到什麼位址都能正確運作的程式碼,使單一一份副本能服務所有人。

為什麼重要:取捨真實而相反。靜態連結給出自足、啟動快、可預測的程式,但它較大、浪費記憶體(每個程式都重複那份程式庫),而且要修一個程式庫錯誤,你得重建每一個程式。動態連結給出較小的可執行檔,讓許多程式共用記憶體中的一份副本,並讓你修補一次程式庫就惠及所有人——但程式現在依賴執行時有正確版本的程式庫存在,於是出現可怕的「找不到 .dll/.so」失敗與版本不符的問題。

二十個程式各自使用一個 2 MB 的數學程式庫。靜態連結的話,那是磁碟與記憶體中二十份 2 MB 的副本(40 MB)。動態連結的話,記憶體中只有一份 2 MB 的共享副本,由全部二十個程式使用。

靜態=自足但重複;動態=共享但依賴程式庫必須存在。

動態連結的便利有其代價:若預期的共享程式庫缺失或版本不對,程式可能失效(DLL 地獄)。靜態連結避開了那種脆弱性,但無法在多個程式間共用記憶體中的單一副本。

又称
static linking versus dynamic linking靜態連結對動態連結