Linux共享庫兩種加載方式簡述

     動態庫技術一般能減小程序的大小,節省空間,提升效率,具備很高的靈活性,對於升級軟件版本也更加容易。與靜態庫不一樣,動態庫裏面的函數不是執行程序自己 的一部分,而是在程序執行時按需載入,其執行代碼能夠同時在多個程序中共享。因爲在編譯過程當中沒法知道動態庫函數的地址,因此須要在運行期間查找,這對程 序的性能會有影響。 程序員

 

共享庫 

     對於共享庫來說,它只包括2個段:只讀的代碼段 和可修改的數據段。堆和棧段,只有進程纔有。若是你在共享庫的函數裏,分配了一塊內存,這段內存將被算在調用該函數的進程的堆中。代碼段因爲其內容是對每 個進程都是同樣的,因此它在系統中是惟一的,系統只爲其分配一塊內存,多個進程之間共享。數據段因爲其內容對每一個進程是不同的,因此在連接到進程空間 後,系統會爲每一個進程建立相應的數據段。也就是說若是一個共享庫被N個進程連接,當這N個進程同時運行時,同時共享一個代碼段,每一個進程擁有一個數據段,系統中共有N個數據段。PICposition independent code,使.so文件的代碼段變爲真正意義上的共享。若是編譯時不加-fPIC,則加載.so文件的代碼段時,代碼段引用的數據對象須要重定位重定位會修改代碼段的內容,這就形成每一個使用這個.so文件代碼段的進程在內核裏都會生成這個.so文件代碼段的copy。 函數

 

加載方式

     1. 靜態加載 性能

 

     在程序編譯的時候加上-l」選項,指定其所依賴的動態庫,這個庫的名字將記錄在ELF文件的.dynamic節。在程序運行時,loader會預先將程序所依賴的全部動態庫都加載在進程空間中。 編碼

     優勢:動態庫的接口調用簡單,能夠直接調用。 spa

     缺點:動態庫的生存週期等於進程的生存週期,其加載時機不靈活。 code

 

     2. 動態加載 orm

     在程序中編碼來指定加載動態庫的時機,常常使用的函數dlopen和dlclosehtm

     優勢:動態庫加載的時機很是靈活,能夠很是細緻的定義動態庫的生存週期。 對象

     缺點動態庫的接口調用起來比較麻煩,同時還要關注動態庫的生存週期。 接口

=====================================================

      #include <dlfcn.h>

  void * dlopen( const char * pathname, int mode );

  函數描述:

  在dlopen的()函數以指定模式打開指定的動態鏈接庫文件,並返回一個句柄給調用進程。使用dlclose()來卸載打開的庫。

  mode:分爲這兩種

  RTLD_LAZY 暫緩決定,等有須要時再解出符號

  RTLD_NOW 當即決定,返回前解除全部未決定的符號。

  RTLD_LOCAL  不容許導出符號

  RTLD_GLOBAL 容許導出符號

  RTLD_NODELETE

      RTLD_NOLOAD

      RTLD_DEEPBIND          //具體含義可經過man查看dlopen函數說明

  返回值:

  打開錯誤返回NULL

  成功,返回庫引用

  編譯時候要加入 -ldl (指定dl庫)

 

  int dlclose (void *handle);

 

  函數描述:

   dlclose用於關閉指定句柄的動態連接庫,只有當此動態連接庫的使用計數爲0時,纔會真正被系統卸載。

 

 

     在dlopen一個共享庫時,

a、進程會加載該共享庫的代碼段和數據段,同時爲這個共享庫計數加1

b、進程查找該共享庫的dynamic節,查看其所依賴的共享庫。

c、首先檢查所依賴庫是否已經被加載,若是已被加載,則爲這個共享庫計數加1。若是未被加載,則加載其代碼段和數據段,而後爲這個共享庫計數加1

d、再查找這些庫所依賴的庫。最終進程會爲每一個加載的共享庫維護一個依賴的計數。

 

     在dlclose共享庫時:

a、首先將該共享庫的計數減1,若是該共享庫依賴計數爲0,則卸載該共享庫。

b、在dynamic節中,查找其所依賴的共享庫。

c、爲每一個共享庫的計數減1,若是該共享庫依賴計數爲0,則卸載該共享庫。

d、重複上面的步驟。

  • 優勢:

a、能夠在程序啓動的時候,減小加載庫的數量,這樣能夠加快進程的啓動速度和減小加載庫的內存使用。

b、爲進程提供了卸載共享庫的機會,這樣就能夠回收共享庫代碼段和數據段所佔用的內存。

  • 缺點:

對於程序員編碼來說,會產生必定的疑惑。一個static的對象的生存週期是貫穿在進程始終的,實際上不是這樣。在動態庫中的static對象,其生命週期等於該動態庫的生命週期。採用靜態連接的方式,動態庫的生命週期等於進程的生命週期;而採用動態加載的方式,則是不一樣的。

 

參考:

《嵌入式Linux內存與性能詳解》

相關文章
相關標籤/搜索