用到动态库的程序运行过程

当我们写好了一段代码然后编译运行后会生成可执行文件,该文件会存在磁盘的当前目录下,而当我们开始运行这段程序时,操作系统(加载器)需要将其从磁盘加载进内存然后执行相关操作,而对于用到动态库的程序,同时也会将动态库加载进内存中。
以下的讲解以Linux操作系统为例。
进程地址空间
在此之前首先我们来认识一下进程地址空间:
首先我们要知道进程地址空间是每一个进程独有的一份虚拟地址空间,并不是物理上的地址空间,地址空间存在的意义就是更好的划分和管理进程数据, 而实际上是采用页表来与物理地址构建联系的。而当CPU处理虚拟地址中的数据时,操作系统的MMU(内存管理单元)主要负责虚拟地址和物理地址之间的转换。

代码段
我们程序其实就是从main函数开始的一个个函数集合。而这一个个函数(不包括变量)其实本质上就是一系列的指令组合,所以函数指令其实就是存储在代码段。而这函数指令是不可修改的,也就是只读权限。
数据段
数据段包括已初始化数据段和未初始化数据段。而初始化数据段又包括全局变量和静态变量,而未初始化数据段也就是未初始化的全局变量和静态变量。其实数据段也叫做全局区和静态区。
堆区(向上增长)
堆区主要负责动态内存分配,如我们C语言的malloc函数和C++的new运算符,都是常见的用来申请堆区空间的,而堆空间要记得使用过后释放,否则会造成内存泄漏的风险,最终导致程序内存不足而卡死。
共享区
共享区属于内存映射段的一种,而内存映射段主要是用于将磁盘文件内容映射到虚拟内存中的,这其中就设计到页表和缺页中断。而我们所说的共享区是主要用来进行共享库加载和进程间通信使用的。其实共享就是多个进程共享的数据,其实就是在内存中其实只有一份,但每个进程的虚拟地址空间都会映射一份。
栈区(向下增长)
栈区用于存储局部变量,函数参数以及函数调用的返回地址信息。而我们每当调用一个函数时,其所用到的这些数据都会存在栈区,而其他的函数指令就存在代码段。
命令行参数和环境变量
- 命令行参数其实就是我们main函数原型的参数:
int main(int argc,const char* agrv[])而我们在运行可执行程序时附带的参数其实都会当作调用main函数的参数传递过去,而argc就是参数数量,argv就是参数内容。如:ls -a -l其实就是就是-a和-l就是参数,而argv[0]就是ls,也就是程序名。
- 环境变量存储量了用户定义的全局设置信息,如:PATH环境变量就定义了系统训中可执行文件的目录,如ls指令其实就是一个可执行程序,而我们自己写的可执行程序需要加上./才可以运行。而ls不需要的原因就是ls程序的所在路径已经设置进了PATH环境变量内部。
内核区
内核区是供给操作系统使用的区域,其中存放的是内核的代码和数据,如系统调用函数和内核全局变量等信息。而且内核区还负责管理进程的PCB。
而内核区的存在就保证了内核不受用户的干扰,也就是当我们调用内核数据时需要访问内核区,然后调用内核区的调用接口从而进行内核数据的访问与接收等。而且每个进程虚拟地址空间的内核区都是独立的(物理上共一份),所以程序间不会进行互相干扰。
程序运行时操作系统的工作
就绪工作
创建进程
操作系统内核会在内存管理中划分专门的区域为该程序创建一个进程PCB,从而对该进程进行管理。而PCB中的部分信息会被直接初始化,如:进程pid、进程状态(就绪态)、进程默认优先级、程序计数器(记录程序的入口地址)。并且会为进程分配一个独立的虚拟地址空间。
资源分配
初始的内存大小分配、CPU调度时间分配(具体时间取决于后期CPU调度时会根据调度算法进行时间分配)。
程序加载
就绪工作做完以后,加载器就会将程序从磁盘加载进内存,也就是创建地址空间。实际上就是通过解析磁盘文件的ELF格式来确定程序的入口和代码段数据段的位置,如果程序链接了动态库的话还会记录所用到的动态库函数在内存中的加载位置。然后开始按照程序文件信息,将程序的代码段、数据段分别加载到分配好的内存区域中。对于共享数据部分会先进行检查内存中是否已经存在,如果存在的话后续就直接页表映射,不存在的话就加载进内存中。
建立程序执行环境
也就是将PCB中的字段进行赋值的过程。将程序计数器设置为程序的入口地址。初始化栈指针ESP寄存器,为栈空间分配初始地址(寄存器中存的都是虚拟地址)。同时还会进行其他的寄存器数据的初始化。
页表操作
页表就是建立虚拟内存和物理内存的映射关系,新加载进内存的数据直接在页表中构建映射关系。对于映射关系中的物理地址如果不存在时则会发生缺页中断,根据页面信息在磁盘的位置进而找到对应页面,将其读进物理内存中,同时进行页表的更新。
我们的程序在编译链接形成可执行程序时,此时还没有进行运行,也就没有加载进内存,但是其内部代码数据就已经采用虚拟地址进行编址好了,也称作逻辑地址。当加载进内存以后,其内部代码数据就都会有对应的一个物理地址。所以此时页表也就构建出K-V结构的映射关系。但是页表并不是一次性完成所有页面的映射,对于动态分配的数据和还未访问的数据部分,其页表项并未填充。
调度执行
操作系统在就绪队列中根据调度算法选择一个进程进行执行,此时程序才正式开始运行。
动静态库对比
- 静态库在编译链接的过程中就直接将程序代码中所用到的静态库方法直接拷贝进可执行程序里。然后在运行的时候就将含有静态库方法的可执行程序一起加载进内存中。所以我们多个程序运行都用到了同一个静态库的话,那么内存中就会存在多份,此时对于内存空间就是一种极大的浪费。
- 动态库则是在程序运行的过程中被加载进物理空间中,而动态库中的方法被调用时才会将动态库加载进共享区。动态库在物理内存中只会存在一份,而每个使用了动态库的进程会在个地址空间的共享区中通过页表直接和物理内存中的动态库构建映射关系。动态库的共享区从而就节省了内存空间。
首先我们知道当形成动态库时,编译和静态库一样,需要包含库文件的路径与库名称,但是在运行时,静态库可以直接进行运行,而动态库运行时需要和库文件在同一目录下或者建立软链接,或者将库文件拷贝到lib64目录下,这样在运行时就会默认去该库下寻找所需库文件,或者直接去/exc/ld.so.conf.d目录下更改动态库配置文件,也就是创建一个文件,同时将我们库的绝对路径写进文件中。因为动态库并没有将库中的数据拷贝进代码中,所以在运行时需要寻找动态库的所在位置,然后才可以调用动态库中的方法。而且动态库形成过程时,生成.o文件时需要带上-fPIC(与位置无关码)。
地址空间中的函数调用
函数调用
在程序进行编译时,会通过程序入口地址确定函数的偏移地址。在链接阶段这些相对地址会在虚拟地址空间中转换成绝对地址。后续在虚拟地址的代码段中进行函数调用时直接通过存放下一条指令地址的寄存器找到函数入口地址直接进行调用函数。
动态库函数调用
动态库由于是在程序运行时才加载进虚拟地址空间的共享区,但是动态库在虚拟地址空间的加载位置是不确定的,所以说,动态库中的函数地址也是不确定的。而想要通过虚拟地址调用对应的动态库函数就与动态库生成与位置无关码有关联。
需要用到动态库的程序被编译生成可执行程序时,其会保存所用动态库函数的一个相对偏移量。也就是所调用的动态库函数相对于动态库的起始未知的偏移量。而当程序运行时,动态库的信息和程序用到动态库函数的偏移量关系也会加载进内存中。而且当程序的代码段中使用到了对应动态库中的函数方法时,动态链接器才开始将动态库加载进虚拟内存的共享区中的某个位置,从而就确定好了库的起始地址,那么通过偏移量就可以将库函数映射到共享区中的具体位置(那么说也就确定了绝对地址)。那么当程序调用动态库函数时,通过动态库起始地址+偏移量的方式进行调用对应动态库函数。
相关文章:
用到动态库的程序运行过程
当我们写好了一段代码然后编译运行后会生成可执行文件,该文件会存在磁盘的当前目录下,而当我们开始运行这段程序时,操作系统(加载器)需要将其从磁盘加载进内存然后执行相关操作,而对于用到动态库的程序&…...
类型转换与IO流:C++世界的变形与交互之道
文章目录 前言🎄一、类型转换🎈1.1 隐式类型转换🎈1.2 显式类型转换🎁1. C 风格强制类型转换🎁2. C 类型转换操作符 🎈1.3 C 类型转换操作符详解🎁1. static_cast🎁2. dynamic_cast&…...
Pytorch使用手册- TorchVision目标检测微调Tutorial的使用指南(专题十二)
这篇教程的目标是对一个预训练的 Mask R-CNN 模型进行微调,应用于 Penn-Fudan 行人检测与分割数据集。该数据集包含 170 张图像,里面有 345 个行人实例,我们将通过这个教程来演示如何使用 torchvision 中的新特性,训练一个面向自定义数据集的目标检测和实例分割模型。 注意…...
人工智能机器学习算法分类全解析
目录 一、引言 二、机器学习算法分类概述 (一)基于学习方式的分类 1. 监督学习(Supervised Learning) 2. 无监督学习(Unsupervised Learning) 3. 强化学习(Reinforcement Learning…...
Linux 35.6 + JetPack v5.1.4@DeepStream安装
Linux 35.6 JetPack v5.1.4DeepStream安装 1. 源由2. 步骤Step 1 安装Jetpack 5.1.4 L4T 35.6Step 2 安装依赖组件Step 3 安装librdkafkaStep 4 安装 DeepStream SDKStep 5 测试 deepstream-appStep 6 运行 deepstream-app 3. 总结3.1 版本问题3.2 二进制help 4. 参考资料 1. …...
图数据库 | 11、图数据库架构设计——高性能图存储架构(下)
在上篇内容中,老夫着重讲了高性能图存储系统的特点,咱们继续往下讲重点——高性能存储架构的设计思路!! 2.高性能存储架构设计思路 首先呢,存储架构以及核心数据结构的设计思路通常围绕如下4个维度来进行:…...
【HTTP】HTTP协议
一个Web Server就是个服务器软件(程序),或者是运行这个服务器软件的硬件(计算机),其主要功能是通过HTTP协议与客户端进行通信,来接收,存储,处理来自客户端的HTTP请求&…...
大数据新视界 -- Hive 基于 MapReduce 的执行原理(上)(23 / 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...
SpringBoot源码解析(六):打印Banner
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
【计算机网络】实验6:IPV4地址的构造超网及IP数据报
实验 6:IPV4地址的构造超网及IP数据报 一、 实验目的 加深对IPV4地址的构造超网(无分类编制)的了解。 加深对IP数据包的发送和转发流程的了解。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实验内容 1、了解IPV4地址的构造超网…...
easy excel 生成excel 文件
导包 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.3</version> </dependency> 内容 List<类> limspjreport 值; String fileName sdf.format(new Date()) "-…...
Ajax:回忆与节点
一点回忆 面对我的Ajax学习,实现前后端交互,最开始我采用的使用网络寻找intellij IDEA Ultimate破解方法,然后最终成功,然后按照相关教程配置java ee项目,然后中间又去配置了Tomcat服务器,然后又去学习了一…...
Python+OpenCV系列:Python和OpenCV的结合和发展
PythonOpenCV系列:Python和OpenCV的结合和发展 **引言****Python语言的发展****1.1 Python的诞生与发展****1.2 Python的核心特性与优势****1.3 Python的应用领域** **OpenCV的发展****2.1 OpenCV的起源与发展****2.2 OpenCV的功能特性****2.3 OpenCV的应用场景** *…...
Ubuntu20.04 由源码编译安装opencv3.2 OpenCV
Ubuntu20.04 由源码编译安装opencv3.2.0 获取 opencv 及opencv_contrib源代码 创建目录以存放opencv及opencv_contrib源代码 mkdir ~/opencv3.2.0 cd ~/opencv3.2.0获取opencv源代码并切换到对应tag git clone https://github.com/opencv/opencv.git cd opencv git checkou…...
A058-基于Spring Boot的餐饮管理系统的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...
RDIFramework.NET CS敏捷开发框架 SOA服务三种访问(直连、WCF、WebAPI)方式
1、介绍 在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。…...
Linux——命名管道及日志
linux——进程间通信及管道的应用场景-CSDN博客 文章目录 目录 文章目录 前言 一、命名管道是什么? 理解: 2、编写代码 makefile 管道封装成类,想用中管道时只需要调用实例化 读端 写端 日志 1、日志是什么? 2、日志有什么&#x…...
Flink 常见面试题
1、Flink 的四大特征(基石) checkpoin基于Chandy-Lamport算法实现了分布式一致性快照提供了一致性的语义 state丰富的StateAPI time实现了Watermark机制,乱序数据处理,迟到数据容忍 window开箱即用的滚动,滑动会话窗口…...
rtc-pcf8563 0-0051: low voltage detected, date/time is not reliable
解决方法: 1、先测量pcf8563电源电压,是否满足要求。 2、pcf8563首次操作。第一次读取pcf8563的时间,未初始化,非法,芯片门槛电压检测配置不合理。使用hwclock命令写入一次,即可解决。 hwclock -f /dev/…...
(简单5步实现)部署本地AI大语言模型聊天系统:Chatbox AI + grok2.0大模型
摘要: 本文将指导您如何部署一个本地AI大语言模型聊天系统,使用Chatbox AI客户端应用和grok-beta大模型,以实现高效、智能的聊天体验。 引言: 由马斯克X-AI发布的Grok 2大模型以其卓越的性能超越了GPT4.0。Grok模型支持超长文本…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
