大家好,又见面了,我是你们的朋友全栈君。
总结一:动态库
前言
我们知道程序编译链接经常使用动态,同时我们可能还知道,动态库时程序运行时加载的。但是动态库到底有什么作用,如何生成、如何加载等,我们却很少关注。接下来,我给大家做一个简单的介绍。
1.1 动态库和静态库的区别
静态库特点(linux):
动态库的特点(linux)
对于工程中比较共通的源码文件,比如多个进程使用同一个模块的源码,我们最好将其制作成动态库,以节省系统空间。同时如果动态库出现bug,只需要重新生成一个动态库并将以前的替换即可。不需要重新编译其他模块。
1.2 内存中的动态库
在讲到动态库的装载时我们需要懂一定的背景知识,首先虚拟内存和物理内存,其次还有地址映射,这些知识就不在本文多加讲解,网上资料很多。我们动态库在整个内存空间是有一份,而每个进程都有自己的虚拟空间,虚拟空间会使用匿名映射(mmap使用MAP_PRIVATE方式进行映射),使自己的进程与动态库进行关联。本进程只会保留访问动态库时的一些数据。好了,打的方向就说这么多,这几句话随便抽出一个词来都够将好久。我们只需要对大方向有认识即可。以下就是映射表
此外我们说一些额外的小知识,在linux系统中 /proc 目录下有很多进程文件。在执行的进程都会创建一个文件。随便进入一个文件 /etc/1892。查看maps文件(sudo cat maps),这里面对应了动态库对应虚拟空间的位置,值得注意的是,这个文件最后一列有多少个[stack]就有多少个线程
同时我们也可以直接使用readelf -m [bin文件名],来读取该bin文件的链接信息。
1.3 动态库的加载
关于动态库我当初的直接认识是,程序运行到调用该动态库的接口时,会产生缺页,从而去磁盘加载动态库到内存,然后再执行。但事实并非如此。动态库也分为隐式链接和显示链接,不同的方式其载入内存的时间也是大相径庭。
由以上两点我们可以看出显示链接如果控制得当,对内存的消耗将下降许多,大型项目应该使用显示链接。但是缺点也有,就是如果库不存在,隐式链接可以再一开始就发现库不存在,而显示链接会被偶然触发。
1.4 动态库的制作
首先我们准备一个源文件 print.c
输入指令
由此我们生成了 libprint.so动态库。
然后我们再创建libcurl.so 的接口头文件print.h
1.5 动态库的隐式链接
我们创建main.c 去使用库
输入指令
生成target
执行 https://cloud.tencent.com/developer/article/target, 输出如下
我们可以通过 readelf -d target,可以查看target链接了libprint.so
接下来我们删除 libprint.so。 然后再运行target,这时我们发现出现如下错误
这说明程序在一开始就要加载libprint.so的库,这就是动态库的隐式链接
1.6 动态库的显式链接
这时我们需要更改main.c的内容,修改最终如下
同时我们gcc 中还需要加上 libdl.so库
此时我们删除 libprint.so。然后再执行target 文件。发现程序运行了一段时间,到使用库时才报错
由此我们可以看出动态库的显示连接才能真正实现使用时才去调用。
附录 : makefile
在这里我给出这个小工程的makefile
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/187491.html原文链接:https://javaforall.cn

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/144603.html