通俗举例讲解动态链接】静态链接
参考动态链接 - 知乎
加上我自己的理解,比较好懂,但可能在细节方面有偏差,但总体是一致的
静态链接的背景
静态链接使得不同的程序开发者和部门能够相对独立的开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率,原先现在程序规模也随之扩大。
但静态链接的缺点也暴露出来:浪费内存、磁盘空间、模块更新困难(耦合性太强)。
内存与磁盘空间
静态链接在计算机早期还是比较流行的,但是到了后面,其缺点也非常明显。比如浪费内存和磁盘空间,更新模块困难等。
一个文件的转换进程
hello.c(源程序[文本])->预处理器(cpp)->hello.i(修改了的源程序[文本])->编译器(ccl)->hello.s(汇编程序[文本])->汇编器(as)->hello.o(可重定位目标程序[二进制])->链接器(ld)->hello(可执行目标程序[二进制])
只需要注意:
hello.c:源文件
hello.o:由hello.c编译而来
hello(可执行目标程序[二进制]),最终执行文件。
比如我有a.cpp ,a.h,b.cpp c.cpp四个文件
a.cpp 定义了一个函数sayHello
#include <iostream>
void sayHello(){std::cout<<"hello world!";
}
a.h
#ifndef UNTITLED1_A_H
#define UNTITLED1_A_Hvoid sayHello();#endif //UNTITLED1_A_H
b.cpp 调用了a的函数sayHello
#include "a.h"
int main(){sayHello();
}
c.cpp 调用了a的函数sayHello
#include "a.h"
int main(){sayHello();
}
静态链接
如果运行b那么就会结合b.o,以及其调用的a.o生成可执行文件。c运行会另外调用 c.o,a.o生成可执行文件,此时可执行文件可以认为长这样
#include <iostream>
void sayHello(){std::cout<<"hello world!";
}
int main(){sayHello();
}
此时a.o重复了两次,但这两个a.o保存了相同的内容,浪费内存和磁盘。
再比如Program1 & Program2分别包含Program1.o和Program2.o两个模块,并且还共用了Lib.o这个模块。静态链接下,P1和P2都用到了Lib.o这模块,所以它们同时在链接输出的可执行文件P1和P2有两个副本,当同时运行两个程序,Lib.o在磁盘和内存中都有两个副本,浪费空间。
程序开发与发布
静态链接另一个问题是对程序的更新,部署和发布也会很麻烦,我如果在a中更新了sayHello,那么生成的b,c可执行文件里的sayHello还是老的,需要重新连接,很麻烦耦合度很高。
程序有任何模块更新,整个程序就要重新链接,发布给用户,
动态链接
dll文件和so文件
dll文件和so文件都是动态链接库,也叫共享对象文件
动态链接原理
动态链接库就是将程序模块相互独立的分隔开来,形成独立的文件,不再将它们静态地链接到一起。简单而言就是对那些组成程序目标文件的链接,等到程序运行时才进行链接,也就是把链接的过程推迟到运行时才进行,这就是动态链接的基本思想。
动态链接没有提前链接的过程,但一般文件都是动态和静态链接结合使用,也有生成可执行文件这一步。
比如我编译a.cpp为共享对象文件a.so,还有a.h
b.cpp为c.o,此时我运行生成可执行文件,生成时侦测到sayHello为动态链接的实现,所以就不执行链接(如果侦测到为静态文件,那么就还是老样子进行链接)
b可执行文件执行时,遇到sayHello,就去动态库so中找这个函数的实现位置,这个找的位置有几类,我们经常用的是一个环境变量,叫LD_LABRARY_PATH,假设这里找到了,找到之后就将a.so加载到内存,链接,进行执行。
c执行时再用到a.so,此时a.so以及被加载到了内存中,所以不用再重新加载了,直接链接就能使用了。
那也就说明了动态链接的其他特点:
动态运行b.cpp之前必须要有a.so和a.h才能运行,所需的动态库本地必须齐全。
动态链接库的存储位置以及名称
lib文件的名称,要和头文件相呼应,不然怎么找对应的lib呢。
比如
cudnn.h对应libcudnn.so
cudnn_adv_infer.h对应libcudnn_adv_infer.so等等
每一个头文件都要有唯一的一个对应的so文件。
一般so文件会存在lib下,头文件存在include下
如cuda11.6



可以看到
再比如我们c++原生的一些实现
头文件也是在include下,可以看到我们的老熟人头文件iostream等等

模块
静态链接中,整个程序最终只有一个可执行文件,它是一个不可以分割的整体,但是在动态链接下,一个程序被分成了若干个文件,有程序的主要部分,即可执行文件(Program1)和
程序所依赖的共享对象(Lib.so),很多时候把这些部分叫做模块,即动态链接下的可执行文件和共享对象都可以看做是程序的一个模块
当程序模块Program1.c被编译成Program1.o时,编译器还不不知道foobar函数的地址,当链接器将Program1.o链接成可执行文件时,这时候链接器必须确定Program1.o中所引用的foobar函数的性质。
- 如果foobar是一个定义与其它静态目标模块中函数,那么链接器将会按照静态链接的规则,将Program1.o中的foobar地址引用重定位
- 如果foobar是一个定义在某个动态共享对象中的函数,那么链接器就会将这个符号的引用标记为一个动态链接的符号,不对它进行地址重定位,把这个过程留到装载时再进行
程序如何找到用到的动态库以及查看用到的动态库
动态库的搜索顺序如下:
- LD_PRELOAD环境变量指定库路径
- -rpath链接时指定路径
- LD_LIBRARY_PATH环境变量设置路径
- /etc/ld.so.conf配置文件指定路径
- 默认共享库路径,/usr/lib,lib
应该就是按顺序一个一个寻找,直到找到满足要求的实现的动态库为止。
程序是如何找到动态库的? | 守望的个人博客
相关文章:
通俗举例讲解动态链接】静态链接
参考动态链接 - 知乎 加上我自己的理解,比较好懂,但可能在细节方面有偏差,但总体是一致的 静态链接的背景 静态链接使得不同的程序开发者和部门能够相对独立的开发和测试自己的程序模块,从某种意义上来讲大大促进了程序开发的效率…...
K8S部署常见问题归纳
目录一. 常用错误发现手段二、错误问题1. token 过期2. 时间同步问题3. docker Cgroup Driver 不是systemd4. Failed to create cgroup(未验证)子节点误执行kubeadm reset一. 常用错误发现手段 我们在部署经常看到的提示是: [kubelet-check] It seems …...
Redis高可用
最近离职后还没开始找工作,在找工作前去学习一下Redis高可用方案。 目录Redis高可用高可用的概念实现方式持久化主从复制简单结构优化结构优缺点哨兵模式(Sentinel)哨兵进程的作用自动故障迁移(Automatic failover)优缺点集群优缺点Redis高可…...
Hyperledger Fabric 2.2版本环境搭建
前言 部署环境: CentOS7.9 提前安装好以下工具 git客户端golangdockerdocker-composecurl工具 以下是个人使用的版本 git: 2.39.2golang: 1.18.6docker: 23.0.3dockkekr-compose: v2.17.2curl: 7.29.0 官方文档参考链接:跳转链接,不同的版本对应的官…...
macOS Monterey 12.6.5 (21G531) Boot ISO 原版可引导镜像
本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 2023 年 4 月 10 日(北京…...
【软件设计师13】数据库设计
数据库设计 1. 数据库设计过程 2. E-R模型 3. E-R图向关系模型的转换 例如一对一联系,可以将联系单独做为关系模式,也可以存放到任意一个实体中 而一对多要合并只能合并到多这边,不能存放到1 多对多则联系必须单独转成一个关系模式 4. 案…...
SpringMVC的全注解开发
文章目录一、spring-mvc.xml 中组件转化为注解形式二、DispatcherServlet加载核心配置类三、消除web.xml一、spring-mvc.xml 中组件转化为注解形式 跟之前全注解开发思路一致, xml配置文件使用核心配置类替代,xml中的标签使用对应的注解替代 <!-- 组件…...
C# | 导出DataGridView中的数据到Excel、CSV、TXT
C# | 导出DataGridView中的数据到Excel、CSV、TXT 文章目录C# | 导出DataGridView中的数据到Excel、CSV、TXT前言DataGridView数据转存DataTableDataTable转Excel方法一、使用Microsoft.Office.Interop.Excel方法二、使用EPPlus库方法三、使用NPOI库DataTable转CSVDataTable转T…...
新规拉开中国生成式AI“百团大战”序幕?
AI将走向何方? ChatGPT在全球范围掀起的AI热潮正在引发越来越多的讨论,AI该如何管理?AI该如何发展?一系列问题都成为人们热议的焦点。此前,马斯克等海外名人就在网络上呼吁OpenAI暂停ChatGPT的模型训练和迭代…...
日撸 Java 三百行day31
文章目录day31 整数矩阵及其运算面向对象思想java异常处理java中的getter和setter方法代码day31 整数矩阵及其运算 面向对象思想 结合之前day7和day8面向过程开发,只关注了矩阵加法和矩阵乘法的功能。而day31是面向对象开发,一个矩阵类,在这…...
在线绘制思维导图
思维导图是一种可视化的思维工具,它可以将放射性思考具体化为可视的图像和图表。 思维导图利用图文并重的技巧,把各级主题的关系用相互隶属与相关的层级图表现出来,把主题关键词与图像、颜色等建立记忆链接。 它运用图像和颜色等多种元素&…...
月薪20k的性能测试必备技能:发现性能瓶颈掌握性能调优
背景 当下云计算、大数据盛行的背景下,大并发和大吞吐量的需求已经是摆在企业面前的问题了,其中网络的性能要求尤为关键,除了软件本身需要考虑到性能方面的要求,一些硬件上面的优化也是必不可少的。 作为一名测试工作者…...
3、Web前端学习规划:CSS - 学习规划系列文章
CSS作为Web前端开发的第2种重要的语言,笔者建议在学了HTML之后进行。CSS主要是对于HTML做一个渲染,其也带了一些语言语法函数,功能也非常强大。 1、 简介; CSS(层叠样式表)是一种用于描述网页样式的语言。它可以控制网页中的字体、…...
城市轨道交通列车时刻表优化问题【最优题解】
文章目录城市轨道交通列车时刻表优化问题思路文章底部城市轨道交通列车时刻表优化问题 最新进度在文章最下方卡片,加入获取思路数据代码论文:2023十三届MathorCup交流 (第一时间在CSDN分享,文章底部) 题目为数据分析类题目。列车时刻表优化…...
常年不卷,按时下班,工作能力强,同事求助知无不言,不扯皮,不拉帮结派,这样的职场清流竟然被裁掉了!...
在职场上,你永远想不到什么样的员工会被优化,比如下面这位:常年不卷,按时下班,工作很专业,同事问什么都回答,不扯皮,不拉帮结派,简直是职场清流。在上个月竟然被优化了&a…...
基于改进多目标灰狼优化算法的考虑V2G技术的风、光、荷、储微网多目标日前优化调度研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Python 函数、文件与模块
“探索 Python” 这一系列的前几篇文章已为 Python 编程新手介绍了几方面的主题,包括变量、容器对象和复合语句。本文以这些概念为基础,构造一个完整的 Python 程序。引入了 Python 函数和模块,并展示了构建一个 Python 程序、将其存储在文件…...
在Spring Boot微服务使用RedisTemplate操作Redis
记录:400 场景:在Spring Boot微服务使用RedisTemplate操作Redis缓存和队列。 使用ValueOperations操作Redis String字符串;使用ListOperations操作Redis List列表,使用HashOperations操作Redis Hash哈希散列,使用SetO…...
4月软件测试面试太难,吃透这份软件测试面试笔记后,成功跳槽涨薪30K
4 月开始,生活工作渐渐步入正轨,但金三银四却没有往年顺利。昨天跟一位高级架构师的前辈聊天时,聊到今年的面试。有两个感受,一个是今年面邀的次数比往年要低不少,再一个就是很多面试者准备明显不足。不少候选人能力其…...
人人拥有ChatGPT的时代来临了,这次微软很大方!
技术迭代的在一段时间内是均匀发展甚至止步不前的,但在某段时间内会指数级别的爆发。 ChatGPT背后的GPT 3.5训练据说花了几百万美金外加几个月的时间,参数大概有1700多亿。 这对于绝大多数的个人或企业来说绝对是太过昂贵的。 然而,微软&am…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
