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

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

  • 运行时库: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)、定位到占用…

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;你的输出需要从左往右逐行…