一文彻底搞懂静态库和动态库,显示链接和隐式链接

定义:运行时库 静态库 动态库

  • 运行时库: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.mzph.cn/news/444262.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql的cpu高定位

导致数据库CPU很高的原因有很多种,一般和慢SQL也有关(因为每条SQL要么占CPU高,要么占IO高,大体是这样)。 (1)、如果服务器有多个mysql实例,需要通过top命令看看是哪个mysql实例导致的cpu高(如果不是mysql导致的cpu高,需要优化其他导致cpu的程序): (2)、定位到占用…

游戏服务器架构-设计模式之发布订阅模式

发布订阅模式场景 熟悉消息中间件的同学应该对发布/订阅模式(Publish Subscribe Pattern)并不陌生。即使你不了解消息中间件,那么在平时生活中发布/订阅模式也是非常常见的场景。 比如你打开你的微信订阅号,你订阅的作者发布的文章,会广播给每个订阅者。在这个场景里,微信公…

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

前言: 在软件开发和性能测试中,CPU占用率是服务器开发一个很重要的指标,到底有哪些因素会导致CPU占 用率上升呢?又有哪些手段可以降低CPU的占用率呢? 如果你看了这篇文章后仍然没有解决项目问题的思路,请在下方留言或公众号后台留言。(后续我将更新一到两篇…

闲话目前游戏服务器的开发

我是从12年开始进入页游行业,接触到的第一个游戏项目就是淘米网的《摩尔庄园》,公司那个时候也刚在美纽交所上市,被Benson,魏震和Rock腾讯三巨头的感染下,做着喜欢的游戏... (后来在工作中我经常会遇到过不…

危险!!!也许你的web网站或服务正在悄无声息地被SQL注入

2010年秋季,联合国官方网站遭受SQL注入攻击。 2014年一个叫“TeamDigi7al”的黑客组织攻击了美国海军的一个名为“Smart Web Move”的web应用。此次事件直接造成美国海军数据库超过22万服役人员的个人信息被泄露。而事后,美国海军动用了超过50万美元来弥补此次的数据泄密事故…

手把手教你使用sql注入来绕过游戏后台检测

SQL注入毫无疑问是最危险的Web漏洞之一,因为我们将所有信息都存储在数据库中。其解决方案之一,有许多公司实施Web应用程序防火墙和入侵检测/预防系统来试图保护自己。但不幸的是,这些对策往往是不充分的,并且很容易被绕过。 尽管不能依赖防火墙来防止所有SQL注入,但一些防…

设计模式 ---适配器模式

在一些业务场景里,你是否遇到过如下类似的需求: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换…

关于游戏排行榜设计开发的一些总结

前言 不管是手游还是端游,貌似都离不开排行榜,没有排行榜的游戏是没有灵魂的游戏,因为排行榜可以让用户分泌多巴胺,这样日活才会上来,有了用户就有钱赚。产品想方设法的让用户留存,设计各种排行榜:个人段位排名、个人积分或金币排名、全球榜单实时排名。如果用户量少的话…

游戏中的常见概率设计分析

前言游戏中的概率真的是让人又爱又恨,很多玩家因为自己的屌丝气质(白嫖)而弃坑玩不下去的,比如人尽皆知的某阴阳师,除了氪金,还肝,而且如果你的脸真的非常的黑,那也是打不过那些0氪金…

一个通用游戏后台的设计模式实践总结

搞业务开发的时候,发现有一些代码的开发会让人感觉非常简便舒服,有一些代码的开发却有时候会让人感觉心智负担比较大。逐步总结的过程中,发现让开发人员写起来感觉舒服的代码,大概率是因为当前模块与其他模块代码耦合度低&#xf…

使用nginx分片功能提升缓存效率,支持可拖拽式播放视频

Nginx的slice模块可以将一个请求分解成多个子请求,每个子请求返回响应内容的一个片段,让大文件的缓存更有效率。 HTTP Range请求 HTTP客户端下载文件时,如果发生了网络中断,必须重新向服务器发起HTTP请求,这时客户端已经有了文件的一部分,只需要请求剩余的内容,而不需要…

leetcode116. 填充每个节点的下一个右侧节点指针

116. 填充每个节点的下一个右侧节点指针 难度中等128 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下: struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&am…

你的代码是否按照高内聚、低耦合的原则来设计的?

我们一直强调软件开发中要按照高内聚、低耦合的设计原则来做代码结构设计。c语言和c++不同,c语言面向过程、c++面向对象。 真正的项目中,要对业务升级,原来的业务函数需要保留,要保证老的功能继续维持,不能直接删除,这时候c语言面向过程,通常使用回调的方法。c+…

leetcode117. 填充每个节点的下一个右侧节点指针 II

给定一个二叉树 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。 初始状态下,所有 next 指针都被…

你担心大家会滥用的全局变量,大家(包括你自己)一定会滥用

前言 不要使用全局变量的道理大家都懂,基本上在大家学习编程过程中很早就会被教育到,但是有时候我们也会禁不住诱惑用到一些似非实是的全局变量,只不过这些全局变量会穿上马甲,让你不会一下看穿它的巨大危害,滥用全局变量会引申带来其它更为严重的结构性系统问题。…

Android Studio下载安装教程及开发环境搭建

Android Stuio是本次Google io的一大亮点啊,一大早起来就赶紧下载来玩玩了。。。 如果你不幸被墙了,可以去这个帖子下载,我已经上传到百度盘里面了。 [Android利器]Android Studio下载地址来啰 。。http://www.eoeandroid.com/thread-275380-…

暴雪游戏走后,谁来接盘?对网易有何影响?

11月16日,暴雪娱乐公司宣布,由于与网易的现行许可协议将于2023年1月23日到期,将暂停在中国大陆的大部分暴雪游戏服务。这些暴雪游戏包括《魔兽世界》《炉石传说》《守望先锋》《星际争霸》《魔兽争霸 III:重制版》《暗黑破坏神 II…

三次握手与四次挥手

三次握手 三次握手是指在建立TCP连接时,需要client端和server端共进行三次信息确认。 第一次握手:建立连接。client发送连接请求报文段(SYN位置为1,Sequence Number为x),然后,client端进入SYN…

leetcode619. 只出现一次的最大数字(SQL)

表 my_numbers 的 num 字段包含很多数字,其中包括很多重复的数字。 你能写一个 SQL 查询语句,找到只出现过一次的数字中,最大的一个数字吗? --- |num| --- | 8 | | 8 | | 3 | | 3 | | 1 | | 4 | | 5 | | 6 | 对于上面给出的样例…