一文徹底搞懂靜態庫和動態庫,顯示鏈接和隱式鏈接

定義:運行時庫 靜態庫 動態庫

  • 運行時庫:Unix中一個典型的運行時庫例子就是libc,它包含標準的C函數,如,print(),exit()等等,用戶能創建他們自己的運行庫(在Windows中是DLL),而具體的細節依賴編譯器和操作系統的。

  • 靜態庫:函數和數據被編譯進一個二進制文件(通常擴展名為.lib),靜態庫實際上是在鏈接時被鏈接到EXE的,庫本身不需要與可執行文件一起發行。

  • 動態庫:用VC++創建的動態庫包含兩個文件,一個lib文件和一個dll文件,這個lib文件就是引入庫,不是靜態庫,引入庫有時也叫輸入庫或導入庫。

注:windows操作系統下動態庫和運行時庫的擴展名都是.dll,COM組件的擴展名也是.dll,動態庫的引入庫和靜態庫的擴展名都是.lib。

靜態庫的特點和創建過程

靜態庫之所以稱為【靜態庫】,是因為在鏈接階段,會將匯編生成的目標文件.o與引用到的庫一起鏈接打包到可執行文件中。因此對應的鏈接方式稱為靜態鏈接。

  試想一下,靜態庫與匯編生成的目標文件一起鏈接為可執行文件,那么靜態庫必定跟.o文件格式相似。其實一個靜態庫可以簡單看成是一組目標文件(.o/.obj文件)的集合,即很多目標文件經過壓縮打包后形成的一個文件。靜態庫特點總結如下:

  • 靜態庫對函數庫的鏈接是放在編譯時期完成的。

  • 程序在運行時與函數庫再無瓜葛,移植方便。

  • 浪費空間和資源,因為所有相關的目標文件與牽涉到的函數庫被鏈接合成一個可執行文件。

如下圖是靜態庫創建過程:

動態庫的特點和創建過程

為什么還需要動態庫?

  為什么還需要動態庫,其實也就是靜態庫的特點導致。

  • 空間浪費是靜態庫的一個問題。

  • 另一個問題是靜態庫對程序的更新、部署和發布頁會帶來麻煩。如果靜態庫libxx.lib更新了,所有使用它的應用程序都需要重新編譯、發布給用戶(對于玩家來說,只是一個很小的改動,卻導致整個程序重新下載,全量更新)。

  動態庫在程序編譯時并不會被連接到目標代碼中,而是在程序運行是才被載入。不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例,規避了空間浪費問題。動態庫在程序運行時才被載入,也解決了靜態庫對程序的更新、部署和發布頁會帶來麻煩。用戶只需要更新動態庫即可,增量更新

動態庫特點總結:

  • 動態庫把對一些庫函數的鏈接載入推遲到程序運行的時期。 

  • 可以實現進程之間的資源共享。(因此動態庫也稱為共享庫)

  • 將一些程序升級變得簡單。

  • 甚至可以真正做到鏈接載入完全由程序員在程序代碼中控制(顯示調用)。 

?

Windows與Linux執行文件格式不同,在創建動態庫的時候有一些差異。

  • 在Windows系統下的執行文件格式是PE格式,動態庫需要一個DllMain函數做初始化的入口,通常在導出函數的聲明時需要有_declspec(dllexport)關鍵字

  • Linux下gcc編譯的執行文件默認是ELF格式,不需要初始化入口,亦不需要函數做特別的聲明,編寫比較方便。

windows下調用動態庫的方法:

1 隱式加載:即在程序中包含lib文件和.h文件,隱式鏈接有時稱為靜態加載或加載時動態鏈接。例如:

#include "somedll.h"

#pragma comment( lib, "somedll.lib")

然后就可以直接調用此dll中的函數,注意運行時仍然需要somedll.dll。

2 顯示加載:使用loadlibrary,GetProcAddress,FreeLibrary,不需要.h文件和.lib文件,但是要知道函數的原型。顯式鏈接有時稱為動態加載或運行時動態鏈接

3 區別:如果在進程啟動時未找到 DLL,操作系統將終止使用隱式鏈接的進程。同樣是在此情況下,使用顯式鏈接的進程則不會被終止,并可以嘗試從錯誤中恢復。

有關Win32 DLL,Unix共享庫及普通庫的詳細庫結構信息請參考《鏈接器與加載器》一書。

鏈接庫的鏈接方式

1 確定要使用的鏈接方法:

有兩種類型的鏈接:隱式鏈接和顯式鏈接。

隱式鏈接

  1. 應用程序的代碼調用導出 DLL 函數時發生隱式鏈接。當調用可執行文件的源代碼被編譯或被匯編時,DLL 函數調用在對象代碼中生成一個外部函數引用。若要解析此外部引用,應用程序必須與 DLL 的創建者所提供的導入庫(.LIB 文件)鏈接。

  2. 導入庫僅包含加載 DLL 的代碼和實現 DLL 函數調用的代碼。在導入庫中找到外部函數后,會通知鏈接器此函數的代碼在DLL 中。要解析對 DLL 的外部引用,鏈接器只需向可執行文件中添加信息,通知系統在進程啟動時應在何處查找 DLL 代碼。

  3. 系統啟動包含動態鏈接引用的程序時,它使用程序的可執行文件中的信息定位所需的 DLL。如果系統無法定位 DLL,它將終止進程并顯示一個對話框來報告錯誤。否則,系統將 DLL 模塊映射到進程的地址空間中。

  4. 如果任何 DLL 具有(用于初始化代碼和終止代碼的)入口點函數,操作系統將調用此函數。在傳遞到入口點函數的參數中,有一個指定用以指示 DLL 正在附帶到進程的代碼。如果入口點函數沒有返回 TRUE,系統將終止進程并報告錯誤。最后,系統修改進程的可執行代碼以提供 DLL 函數的起始地址。

  5. 與程序代碼的其余部分一樣,DLL 代碼在進程啟動時映射到進程的地址空間中,且僅當需要時才加載到內存中。因此,由 .def 文件用來在 Windows 的早期版本中控制加載的 PRELOAD 和 LOADONCALL 代碼屬性不再具有任何意義。

顯式鏈接
大部分應用程序使用隱式鏈接,因為這是最易于使用的鏈接方法。但是有時也需要顯式鏈接。下面是一些使用顯式鏈接的常見原因:

  1. 直到運行時,應用程序才知道需要加載的 DLL 的名稱。例如,應用程序可能需要從配置文件獲取 DLL 的名稱和導出函數名。

  2. 如果在進程啟動時未找到 DLL,操作系統將終止使用隱式鏈接的進程。同樣是在此情況下,使用顯式鏈接的進程則不會被終止,并可以嘗試從錯誤中恢復。例如,進程可通知用戶所發生的錯誤,并讓用戶指定 DLL 的其他路徑。如果使用隱式鏈接的進程所鏈接到的 DLL 中有任何 DLL 具有失敗的 DllMain 函數,該進程也會被終止。同樣是在此情況下,使用顯式鏈接的進程則不會被終止。

  3. 因為Windows 在應用程序加載時加載所有的 DLL,故隱式鏈接到許多 DLL 的應用程序啟動起來會比較慢。為提高啟動性能,應用程序可隱式鏈接到那些加載后立即需要的 DLL,并等到在需要時顯式鏈接到其他 DLL。

  4. 顯式鏈接下不需將應用程序與導入庫鏈接。如果 DLL 中的更改導致導出序號更改,使用顯式鏈接的應用程序不需重新鏈接(假設它們是用函數名而不是序號值調用 GetProcAddress),而使用隱式鏈接的應用程序必須重新鏈接到新的導入庫。

下面是需要注意的顯式鏈接的兩個缺點:

???????????? 1.?如果 DLL 具有 DllMain 入口點函數,則操作系統在調用 LoadLibrary?的線程上下文中調用此函數。如果由于以前調用了LoadLibrary 但沒有相應地調用 FreeLibrary 函數而導致 DLL 已經附加到進程,則不會調用此入口點函數。如果 DLL 使用 DllMain 函數為進程的每個線程執行初始化,顯式鏈接會造成問題,因為調用 LoadLibrary(或AfxLoadLibrary)時存在的線程將不會初始化。服務器負載高,性能下降,導致無法及時的處理客戶端的請求,可能是服務器硬件本身需要升級,另外一方面是程序自身的bug導致的吞吐量不夠,性能低、還有就是可能是架構問題,比如沒有分布式處理,無法動態擴容,基本上你需要查看內存,CPU,磁盤使用情況,使用top,free ,df等命令來動態查看找到異常指標的進程。

???????????? 2.?如果DLL 將靜態作用域數據聲明為 __declspec(thread),則在顯式鏈接時 DLL會導致保護錯誤。用 LoadLibrary 加載 DLL 后,每當代碼引用此數據時 DLL 就會導致保護錯誤。(靜態作用域數據既包括全局靜態項,也包括局部靜態項。)因此,創建DLL 時應避免使用線程本地存儲區,或者應(在用戶嘗試動態加載時)告訴 DLL 用戶潛在的缺陷。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444262.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444262.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444262.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql的cpu高定位

導致數據庫CPU很高的原因有很多種,一般和慢SQL也有關(因為每條SQL要么占CPU高,要么占IO高,大體是這樣)。 (1)、如果服務器有多個mysql實例,需要通過top命令看看是哪個mysql實例導致的cpu高(如果不是mysql導致的cpu高,需要優化其他導致cpu的程序): (2)、定位到占用…

kubelet內存異常分析

背景: kubelet被重啟后, 內存再次升高, 在游戲啟動后,沒有進入大量玩家的情況下,2天時間占用接近10G,并且持續在增長, CPU偶爾負載高。AWS給出的解釋是containerd v1.4.0版本問題, 以下為內部分析過程。 實際情況 # 整體情況 [ec2-user@server]$ free -h …

游戲服務器架構-設計模式之發布訂閱模式

發布訂閱模式場景 熟悉消息中間件的同學應該對發布/訂閱模式(Publish Subscribe Pattern)并不陌生。即使你不了解消息中間件,那么在平時生活中發布/訂閱模式也是非常常見的場景。 比如你打開你的微信訂閱號,你訂閱的作者發布的文章,會廣播給每個訂閱者。在這個場景里,微信公…

leetcode129. 求根到葉子節點數字之和

給定一個二叉樹,它的每個結點都存放一個 0-9 的數字,每條從根到葉子節點的路徑都代表一個數字。 例如,從根到葉子節點路徑 1->2->3 代表數字 123。 計算從根到葉子節點生成的所有數字之和。 說明: 葉子節點是指沒有子節點的節點。 …

游戲服務器架構-設計模式之觀察者模式和發布訂閱模式真的一樣嗎?

前面我給大家分享了觀察者模式和發布訂閱模式,有人私信給我說這倆不是一樣嘛,大體沒什么區別,我猜測大多數認為這兩者是一樣的可以繼續閱讀這兩篇文章,如果還不能解答你的問題,我相信這篇文章對比兩者的關系會讓你有更深刻的認識。 游戲服務器架構-設計模式之觀察者模式 游…

Struts2中s:iterator/s:iterator標簽的使用:

問題是這樣的&#xff1a; <s:iterator value"zhangjieList"> <s:property value"bb"/> </s:iterator> 我在頁面迭代了list里邊的值&#xff0c;我想限定只顯示100個字怎么做&#xff1f; 解決方案&#xff1a; <s:property valu…

聊一下CPU占用高的解決方案

前言: 在軟件開發和性能測試中,CPU占用率是服務器開發一個很重要的指標,到底有哪些因素會導致CPU占 用率上升呢?又有哪些手段可以降低CPU的占用率呢? 如果你看了這篇文章后仍然沒有解決項目問題的思路,請在下方留言或公眾號后臺留言。(后續我將更新一到兩篇…

一文搞懂 什么是CPU上下文?為什么要切換?如何減少切換?

自從上篇文章聊一下CPU占用高的解決方案更新后,最近收到了一些熱心觀眾的后臺留言,問到的一些問題比較集中的是關于CPU切換. 實際用C/C++,go開發,你會特別注意內存和CPU的使用情況,那些對于CPU使用情況特別關注,或者性能特別關注的朋友可以看看這篇文章,相信看完結尾的示…

leetcode257. 二叉樹的所有路徑

給定一個二叉樹&#xff0c;返回所有從根節點到葉子節點的路徑。 說明: 葉子節點是指沒有子節點的節點。 示例: 輸入: 1 / \ 2 3 \ 5 輸出: ["1->2->5", "1->3"] 解釋: 所有根節點到葉子節點的路徑為: 1->2->5, 1->3 思…

內存優化-如何使用tcmalloc來提升內存性能?提升的結果太不可思議

無論是在游戲開發,或者其他長期運行的服務開發中,對內存的使用一直是架構師或者主程序在最初就要關注的point,如果內存使用不當,頻繁申請釋放內存造成系統負擔過大,性能降低,到最后產生大量內存碎片,無法申請可利用內存,最終宕機,給廣大程序員同學造成長期加班的痛苦。…

內存優化-使用tcmalloc分析解決內存泄漏和內存暴漲問題

其實我一直很想寫關于tcmalloc的內存泄漏檢測的文章,只是一直記不起來該如何下筆,有時項目太忙,在整理這方便的思考過少,另外遇到的問題也不是很多,直到最近用tcmalloc幫A項目排查一些很棘手的內存泄漏問題,有了一定的創作靈感,這才執筆創作,希望能分享給大家。 如果對…

leetcode130. 被圍繞的區域

給定一個二維的矩陣&#xff0c;包含 X 和 O&#xff08;字母 O&#xff09;。 找到所有被 X 圍繞的區域&#xff0c;并將這些區域里所有的 O 用 X 填充。 示例: X X X X X O O X X X O X X O X X 運行你的函數后&#xff0c;矩陣變為&#xff1a; X X X X X X X X X X X X…

閑話目前游戲服務器的開發

我是從12年開始進入頁游行業&#xff0c;接觸到的第一個游戲項目就是淘米網的《摩爾莊園》&#xff0c;公司那個時候也剛在美紐交所上市&#xff0c;被Benson&#xff0c;魏震和Rock騰訊三巨頭的感染下&#xff0c;做著喜歡的游戲... &#xff08;后來在工作中我經常會遇到過不…

為什么我們仍然堅持用C++做游戲服務器

本篇文章純屬文字,不需要配圖。 首先以我個人觀點來說,C ++對于我的吸引力不僅僅是它的技術優點。c++是個龐大而奇怪的語言,很多新領域會選擇這個語言是因為有性能上的需求,但是又拿不準瓶頸會出在哪里,C++是一個什么地方調優都很方便的語言,內存,CPU,線程優先…

危險!!!也許你的web網站或服務正在悄無聲息地被SQL注入

2010年秋季,聯合國官方網站遭受SQL注入攻擊。 2014年一個叫“TeamDigi7al”的黑客組織攻擊了美國海軍的一個名為“Smart Web Move”的web應用。此次事件直接造成美國海軍數據庫超過22萬服役人員的個人信息被泄露。而事后,美國海軍動用了超過50萬美元來彌補此次的數據泄密事故…

手把手教你使用sql注入來繞過游戲后臺檢測

SQL注入毫無疑問是最危險的Web漏洞之一,因為我們將所有信息都存儲在數據庫中。其解決方案之一,有許多公司實施Web應用程序防火墻和入侵檢測/預防系統來試圖保護自己。但不幸的是,這些對策往往是不充分的,并且很容易被繞過。 盡管不能依賴防火墻來防止所有SQL注入,但一些防…

JSON是什么?如何產生的?

JSON&#xff1a;是一種輕量級的數據交換方式&#xff0c;它是基于javascript的一個子集。JSON采用完全獨立于語言的文本格式&#xff0c;但是也使用了類似于C語言家族的習慣這些特性使JSON成為理想的數據交換語言。易于人閱讀和編寫&#xff0c;同時也易于機器解析和生成。 掌…

設計模式 ---適配器模式

在一些業務場景里,你是否遇到過如下類似的需求: 1、系統需要使用現有的類,而此類的接口不符合系統的需要。 2、想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的接口。 3、通過接口轉換…

關于游戲排行榜設計開發的一些總結

前言 不管是手游還是端游,貌似都離不開排行榜,沒有排行榜的游戲是沒有靈魂的游戲,因為排行榜可以讓用戶分泌多巴胺,這樣日活才會上來,有了用戶就有錢賺。產品想方設法的讓用戶留存,設計各種排行榜:個人段位排名、個人積分或金幣排名、全球榜單實時排名。如果用戶量少的話…

leetcode6. Z 字形變換

將一個給定字符串根據給定的行數&#xff0c;以從上往下、從左到右進行 Z 字形排列。 比如輸入字符串為 "LEETCODEISHIRING" 行數為 3 時&#xff0c;排列如下&#xff1a; L C I R E T O E S I I G E D H N 之后&#xff0c;你的輸出需要從左往右逐行…