Executable

為什麼類 Unix 系統在呼叫新函式時會執行新程序?

  • May 1, 2012

為什麼類 Unix 系統在呼叫函式而不是動態庫時會執行新程序?與呼叫動態庫相比,創建新程序在性能方面的成本很高。

類 Unix 系統不會“通過執行新程序來呼叫函式”。他們(現在)擁有與幾乎所有其他相對現代的作業系統一樣的共享庫。

另一方面,Shell 會執行其他程序來完成某些任務。但不是所有的。它們具有內置函式,直接在 shell 中(或通過共享庫)實現,用於最常見和最簡單的任務(echo例如,許多 shell 將其實現為內置函式)。

(順便說一句,Windows cmdshell 在這方面與 Unix shell 沒有什麼不同。)

在現代類 Unix 系統中創建程序肯定比進行程序內函式呼叫更昂貴,但幅度並不大。核心針對快速分叉進行了優化,使用寫入時複製等技術進行地址空間管理以加速程序的“複製”,並共享動態庫的文本(程式碼)頁面。

如果您機器上可以從 shell 腳本呼叫的每個執行檔都實現為共享庫,則:

  • 啟動你的 shell 將花費大量時間(和記憶體)來預先載入所有這些東西(即使有記憶體,動態連結器也有不平凡的工作要做,並且庫有數據部分,而不僅僅是文本部分 - 我們在這裡談論成百上千的圖書館)
  • 您必須按需載入每個必要的庫——可能比啟動程序要快一點,但這裡的優勢真的很薄。並且共享庫的數據部分變得非常難以管理(shell 的全域狀態現在取決於在其地址空間中載入的許多不相關程式碼和數據的狀態)。

因此,對於典型用法,您可能不會獲得太多收益,並且穩定性/複雜性成為更多問題。

另一件事是,單獨的程序模型非常有效地隔離了每個任務(假設虛擬記憶體管理和保護)。在“一切都是庫”模型中,任何實用程序庫中的錯誤都可能污染(即破壞)整個外殼。一些隨機實用程序中的錯誤可能會完全殺死您的 shell 程序。

對於多程序模型,情況並非如此,shell 在其執行的程序中不受該類型錯誤的影響。

別的東西:低耦合。當我現在查看/usr/bin目錄中的內容時,我有:

  • ELF 64 位執行檔,
  • ELF 32 位執行檔,
  • Perl 腳本,
  • Shell 腳本(其中一些執行 Java 程序),
  • Ruby 腳本和
  • Python 腳本

…而且我可能沒有最花哨的系統。您根本不能在同一個過程中混合前兩種類型。讓所有其他的口譯員在程序中根本不切實際。

即使您只查看“本機二進制”文件格式,將“實用程序”之間的介面作為簡單的流和退出程式碼也會使事情變得更簡單。

對實用程序的唯一要求是實現作業系統的 ABI 和系統呼叫。您(幾乎)在不同的實用程序之間沒有依賴關係。對於程序內介面來說,這要麼非常困難,要麼根本不可能,除非你強加諸如“所有東西都必須使用編譯器 Y 的版本 X 編譯,帶有這樣那樣的標誌/設置。

對於某些事情,程序內呼叫在性能方面確實很有意義,而且這些事情已經經常作為 shell 的內置函式完成。對於其餘部分,分離流程模型非常有效,其靈活性是一個很大的優勢。

引用自:https://unix.stackexchange.com/questions/37691