当前位置: 首页 > news >正文

【Linux基础IO篇】深入理解文件系统、动静态库

【Linux基础IO篇】深入理解文件系统、动静态库

目录

  • 【Linux基础IO篇】深入理解文件系统、动静态库
      • 再次理解文件系统
        • 操作系统内存管理模块(基础)
          • 操作系统如何管理内存
        • Linux中task_struct源码结构
      • 动态库和静态库
        • 动静态库介绍:
        • 生成静态库
        • 库搜索路径
        • 生成动态库
        • 使用动态库
        • 运行动态库
        • 使用外部库
        • 库文件名称和引入库的名称

作者:爱写代码的刚子

时间:2023.11.10

前言:进一步理解文件系统,以及动静态库的原理和使用

再次理解文件系统

  • 无法对目录建立硬链接(只有系统可以,root用户也不可以,因为可能会存在对目录建立硬链接的环路问题)
  • 每个目录都有.和…这样的硬链接文件
操作系统内存管理模块(基础)
  • 物理内存的基本单位是1KB,4GB内存有2^32个地址,操作系统将物理内存以4KB为基本单位划分为多个区域(同时我们的可执行程序在磁盘中也以4KB为基本单位划分为多个数据块)我们将物理内存中这个4KB大小的空间叫做页框,将磁盘中的4KB叫做页帧,所以数据交换的单位即为4KB。

【问题】为什么是4KB?

  • 减少IO的次数(减少访问外设的次数)(硬件上)

  • 操作系统中存在基于局部性原理的预加载机制(软件上)

  • 从硬件上和软件上,在对磁盘进行防问时对系统进行提速

【问题】当数据小于4KB时是否造成内存的浪费?

  • 不会,因为文件的属性(文件的大小)会规定内存的大小
操作系统如何管理内存

先描述,再组织!

Linux下会存在struct page结构体对象

struct page
{//page页必要的属性信息
}

32位操作系统下4GB内存中存在100万个页

所以我们会得到一个struct page的数组:

struct page mem_array[1048576];

对内存的管理变成了对数组的增删查改,该数组的下标叫做页号

【问题】如何将将物理地址转化为页号?

  • 将物理地址&0xFFFF F000

我们要访问一个内存,我们只需要先找到这个4KB对应的Page,就能在系统中找到对应的物理页框。

所有申请内存的动作,都是在访问内存page数组
在这里插入图片描述

  • 其中flags表示page的使用状态

所以操作系统申请内存的操作就是将flags里面的比特位(is_used)进行修改(置1)

  • _refcount表示引用计数,写时拷贝是以4KB进行拷贝的。
  • lru表示最近最常使用的数据,想被刷新或者可以刷新的数据可以维护在lru中。

附加了解:

  • 对大块内存申请的伙伴系统算法,对小块内存处理的slab分派器

Linux中task_struct源码结构

linux源码下载

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • inode中包含了文件的属性,要想找到文件的内容,需要找到struct file中的address_space

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

基数树(基树):或称压缩前缀树,是一种更节省空间的Trie(前缀树)。对于基数树的每个节点,如果该节点是确定的子树的话,就和父节点合并。

  • Linux内核中该基数树的叶子结点都会指向一个个的page对象(4kb),这个结构也叫做文件的页缓冲区

  • 文件的内容按照4kb是有偏移量的,每一个数据块相当于有了编号,得到一个int类型的偏移量,其中int里面的32个比特位可以用16进制表示,得到一个地址,将该地址按照字典序到基数树中进行查找,即得到了偏移量和page之间的映射关系。(当我们得到了文件中对应数据的偏移量,即可转化为对应的地址,再从基数树中找到对应的page,将数据保存在page中,未来就可以根据page和偏移量,来确定page的刷新次序)

所以Linux中,每一个进程打开的每一个文件都要有自己的inode属性和自己的文件页缓冲区radix_tree_root结构),需要定期将page中的数据刷新到Date blocks中(刷新机制(IO子系统)较为复杂,因为操作系统中存在非常多的IO请求,进程并不关心page中数据的刷新,这个为驱动层面的知识)

(操作系统会将IO请求用struct request结构管理起来,struct request会将与该请求相关的page放进来,还可以在request写入访问哪个磁盘以及相应的位置(逻辑地址),然后将request请求打给磁盘驱动,由磁盘驱动进行执行,就可以将数据从内存写到磁盘了)

所以操作系统中会存在大量的request队列,IO也需要排队(文件相关的page构建成struct request,再将其封装到IO_request_queue里,所谓的刷新就是将该队列里的struct request一个个地提交给对应的磁盘

当然,为了磁盘能够高效地读取,我们也需要进行IO排序,再进行IO合并,以达到以最少的次数来访问磁盘。


以上由操作系统自动操作,操作系统有一堆线程来进行周期性执行对物理内存中的数据刷新的工作。


动态库和静态库

动静态库介绍:
  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静 态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文 件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

生成静态库

以mymath.c和mymath.h举例:

在这里插入图片描述

在这里插入图片描述

makefile文件:

在这里插入图片描述

make output后会形成lib目录,之后拷贝目录给使用者即可。

在这里插入图片描述

但是我们发现,使用gcc编译时发生错误:

在这里插入图片描述

原因是gcc只会在系统指定的路径下进行搜索或者当前目录(必须和源代码在同一级,在目录里的不算),因为我们系统中不存在我们创建的lib目录,所以发生报错

gcc mymain.c -I +指定目录让编译器在指定目录里面寻找头文件(推荐),或者可以在mymain.c文件中把头文件的地址都带上

在这里插入图片描述

但是我们发现,上面发生了报错,找不到我们定义的Add函数,很明显是链接报错

从下面的图片中我们可以看出如果我们以-c选项进行编译,能编译通过

在这里插入图片描述

为什么?因为编译器找不到静态库,gcc会从系统路径下或者当前路径寻找静态库,由于我们的静态库在lib里面,编译器找不到。

【解决】:

指定静态库的名字:

错误写法:

在这里插入图片描述

==为什么还会出错?==因为库的真实名字为去掉前缀和后缀后剩下的名字!

【正确使用】:

在这里插入图片描述

-I :指定头文件的位置,不需要带头文件名字

-L :指定静态库库的文件目录

-l :指定相应的静态库名字(库名字为去掉后缀和前缀,-l最好紧跟名字


似乎操作有点繁琐,那有没有其他的方法来解决这个问题呢?

既然gcc会自动从系统目录里寻找对应的文件,那我们是否可以将文件拷贝到系统路径下?

  • 对头文件和静态库建立软链接,将它们分别放入系统对应的路径下

在这里插入图片描述

【问题】:按理来说myerrno应该等于1,为什么依旧是0呢?

在这里插入图片描述

【解释】:C语言是按照从右向左进行形参实例化的。

第三方库,往后使用的时候,必定要用gcc -l

errno的的本质是了解出错的原因


ldd +可执行文件查看文件的动静态链接

【问题】:为什么我们看不到mymath这样的静态库?

在这里插入图片描述

【解释】:gcc编译时默认选择动态链接

如果系统中只提供静态链接,gcc则只能对该库进行静态链接,动静态库也可以混合链接

如果系统中需要链接多个库,则gcc可以链接多个库

库搜索路径
  • 从左到右搜索-L指定的目录
  • 由环境变量指定的目录(LIBRARY_PATH)
  • 由系统指定的目录(/usr/lib或者/usr/local/lib)

知道了系统库的搜索路径,我们可以选择将我们库的头文件和静态库拷贝至系统搜索路径下。

在这里插入图片描述

在这里插入图片描述

这两个操作叫做库的安装

拷贝成功:

在这里插入图片描述

但是还是出现了问题:

在这里插入图片描述

为什么编译仍然不会通过?

【解释】:虽然我们将自己的静态库拷贝至系统的路径下,但是gcc只认识系统调用接口和C/C++自己的标准库,所以我们在使用自己的库时还是需要指定名字:

在这里插入图片描述

  • 当然,我们还可以使用软链接的方式(但安装别人的库时并不推荐):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


生成动态库
  • shared: 表示生成共享库格式
  • fPIC:产生位置无关码(position independent code)
  • 库名规则:libxxx.so

在这里插入图片描述

在这里插入图片描述

【问题】:为什么动态库具有可执行权限?

因为动态库不像静态库那样不用加载到内存,==动态库需要像可执行程序那样先加载到内存中!==所以可执行权限的真正意义是:是否像可执行程序那样加载到内存,虽然本身文件不能执行,但是需要其他文件来使用它。

  • 生成静态库和动态库:

在这里插入图片描述

在这里插入图片描述

成功:

在这里插入图片描述

使用动态库

编译选项

  • l:链接动态库,只要库名即可(去掉lib以及版本号)
  • L:链接库所在的路径

与静态库类似的使用方法:

在这里插入图片描述

如果还想链接静态库可以-l静态库名字:

在这里插入图片描述

运行动态库

动态库在运行时可能还是会遇到找不到文件的问题!

【解释】:我们只告诉了编译器动态库的位置,但是我们没有告诉操作系统(加载器),所以加载的时候找不到了

【解决】:

  1. 在系统目录下建立软链接:

在这里插入图片描述

在这里插入图片描述

(或者直接拷贝动态库进系统的共享路径下)

2、导入环境变量:

在这里插入图片描述

(注意不要覆盖掉之前的环境变量,并且不需要加入具体的文件名,只要目录就行了)


还有没有更简单的方法?

ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

在这里插入图片描述

(系统的配置文件,里面存放的是路径)

在这里插入图片描述

在这里插入图片描述

切换成root用户修改test.conf :

在这里插入图片描述

在这里插入图片描述

链接成功!:

在这里插入图片描述

(系统全局范围内,永久有效,重新打开服务器也是有效的!)

总结:

  • 1、拷贝.so文件到系统共享库路径下, 一般指/usr/lib 或/lib64(常用)

  • 2、在系统默认路径的库路径 /usr/lib64/下建立软链接 /lib64

  • 3、更改 LD_LIBRARY_PATH

  • 4、/etc/ld.so.conf.d/ 建立自己的动态库路径配置文件,然后重新ldconfig

实际上我们用的库都是别人成熟的库,都采用直接安装到系统的方式。

使用外部库

系统中其实有很多库,它们通常由一组互相关联的用来完成某项常见工作的函数构成。比如用来处理屏幕显示情况的函数(ncurses库)

ncurses库:基于终端的文本图形和用户交互的库

官网链接

#include <math.h>
#include <stdio.h>
int main(void)
{double x = pow(2.0, 3.0);printf("The cubed is %f\n", x);return 0;
}
gcc -Wall calc.c -o calc -lm

-lm表示要链接libm.so或者libm.a库文件

库文件名称和引入库的名称

如:libc.so -> c库,去掉前缀lib,去掉后缀.so,.a


小总结:

  1. 动态库在进程运行的时候是要被加载的(静态库没有)
  2. 常见的动态库被所有的可执行程序(动态链接的),都要使用动态库(共享库)

所以动态库在系统中加载之后会被所有进程共享!

如何加载?

【解释】:动态库会被加载到进程地址空间的共享区,当代码需要动态链接时直接跳转到共享区,将执行结果返回即可。

【结论】:

  1. 建立映射(磁盘中的动态库数据加载到物理内存,在用页表映射到虚拟内存),从此往后,我们执行到任何代码都是在我们的进程地址空间中执行的!

  2. 系统在运行中一定会存在多个动态库(OS管理,先描述再组织,系统中所有库的加载情况操作系统非常清楚)

【问题】:libc.so中可能会存在errno这样的全局变量,如果有进程修改了errno那是否会影响其他进程使用该动态库呢?

不会,因为会发生写实拷贝这个库一旦被多个人共享,它所在的页就会,引用计数变成2,如果发现是被多个人共享的直接发生写实拷贝


相关文章:

【Linux基础IO篇】深入理解文件系统、动静态库

【Linux基础IO篇】深入理解文件系统、动静态库 目录 【Linux基础IO篇】深入理解文件系统、动静态库再次理解文件系统操作系统内存管理模块&#xff08;基础&#xff09;操作系统如何管理内存 Linux中task_struct源码结构 动态库和静态库动静态库介绍&#xff1a;生成静态库库搜…...

flink 写入 starrocks 报错 too many filtered rows attachment

可能原因1 把你starrocks中DDL里的varchar(...) 先修改为STRING. 一般是因为字段超出定义的长度. 可能原因2 csv里有脏数据 导致3列被切分为4列 ....PRIMARY KEY (id) NOT ENFORCED ) WITH (connector starrocks,jdbc-url ...,username ...,password ...,database-nam…...

Windows 安装 Maven

目录 安装 JDK下载 Maven配置阿里云镜像配置环境变量 安装 JDK Windows 安装 JDK 下载 Maven 下载地址&#xff1a;https://maven.apache.org/download.cgi 下载 apache-maven-3.9.5-bin.zip 到本地解压到 D:\Software\apache-maven-3.9.5 配置阿里云镜像 配置阿里云远程仓…...

一文读懂关于IPv6的那些事

作为下一代互联网的战略发展方向&#xff0c;我国正加速IPv6的升级改造&#xff0c;目前从网络基础设施如运营商骨干网、城域网到互联网服务商如各类云服务以及包括手机、电脑、路由器等终端设备厂商都开始支持IPv6网络。那么到底什么是IPv6&#xff1f;IPv6有哪些特点呢&#…...

数据结构—队列的实现

前言&#xff1a;上次我们已经学习了数据结构中一个重要的线性表—栈&#xff0c;那么我们这一次就来学习另外一个重要的线性表—队列。 目录&#xff1a; 一、 队列的概念 二、 队列的实现&#xff1a; 1.队列的创建 三、 队列的操作 1.初始化队列 2.队尾入队列 3.队头出队列…...

Linux_shell脚本中的stty

shell脚本中的stty stty是用于配置终端&#xff08;tty&#xff09;设置的命令。它允许用户查看和修改与终端相关的各种参数。下面是stty命令的一些常见用法和参数&#xff1a; 基本语法&#xff1a; stty [OPTION] [SETTING]常见选项和参数&#xff1a; 基本设置&#xff1…...

HTML转PDF模板

一、准备pom依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>html2pdf</artifactId><version>1.0.2</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId&g…...

Clickhouse学习笔记(14)—— Clickhouse监控

ClickHouse 运行时会将一些个自身的运行状态记录到众多系统表中&#xff0c;如下所示&#xff1a; 为了直观方便地监控ck的运行情况&#xff0c;使用Prometheus Grafana 的组合来进行监控 Prometheus 负责收集各类系统的运行指标&#xff1b;Grafana 负责可视化 Prometheus&a…...

Vue3 + Three.js + gltf-pipeline大型园区场景渲染与3D业务

在非使用unity作为3D渲染方案的前提下&#xff0c;对与目前web开发者比较友好的除了canvas场景需要的2D babylon.js&#xff0c;fabric.js, Three.js是目前针对于jsWeb用户最直接且比较友好的3D引擎方案了。 准备工作&#xff1a; 1.明确需要用的场景方案都有那些&#xff0c;模…...

基于FPGA的PS端的Si5340的控制

1、功能 Si5340/41-D可以输出任意频率&#xff0c;当然有范围&#xff0c;100Hz1GHz。外部输入为24M或者4854M的XTAL&#xff0c;VCO在13500~14256Mhz之间&#xff0c;控制接口采用IIC或者SPI。 芯片架构图 2、IIC控制方式 3、直接上控制代码 使用米联客ZU3EG&#xff0c;将…...

安装 Lua 的 HTTP 库

首先&#xff0c;你需要安装 Lua 的 HTTP 库。可以使用 LuaRocks 来安装。以下是安装命令&#xff1a; luarocks install http然后&#xff0c;你可以使用以下代码来爬取网页内容&#xff1a; local http require http-- 设置代理信息 http.set_proxy(jshk.com.cn)-- 网页UR…...

Redis解决缓存问题

目录 一、引言二、缓存三、Redis缓存四、缓存一致性1.缓存更新策略2.主动更新 五、缓存穿透六、缓存雪崩七、缓存击穿1.基于互斥锁解决具体业务2.基于逻辑过期解决具体业务 一、引言 在一些大型的网站中会有十分庞大的用户访问流量&#xff0c;而过多的用户访问对我们的MySQL数…...

七个合法学习黑客技术的网站,让你从萌新成为大佬

大家好我是若风&#xff0c;一个8年网络安全攻防经验的白帽黑客。 合法的学习网站&#xff0c;以下这些网站&#xff0c;虽说不上全方位的满足你的需求&#xff0c;但是大部分也都能。能带你了解到黑客有关的技术&#xff0c;视频&#xff0c;电子书&#xff0c;实践&#xff0…...

【数据结构】面试OJ题——带环链表(数学推论)

目录 1.环形链表Ⅰ ​编辑 思路 &#xff1a; 思路拓展 问题一&#xff1a; 问题二&#xff1a; 总结&#xff1a; 问题三&#xff1a; 证明总结第三点 总结&#xff1a; 2. 环形链表Ⅱ 思路一 思路二 3.相交链表 思路&#xff1a; 1.环形链表Ⅰ 141. 环形链…...

PostgreSQL中pg_ctl工具的使用

pg_ctl工具有以下功能&#xff1a; &#xff08;1&#xff09;初始化postgresql数据库实例 &#xff08;2&#xff09;启动、终止或重启postgresql数据库服务 &#xff08;3&#xff09;查看postgresql数据库服务的状态 &#xff08;4&#xff09;让数据库实例重新读取配置…...

深入理解Kafka3.6.0的核心概念,搭建与使用

Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的&#xff08;replica&#xff09;&#xff0c;基于zookeeper协调的分布式消息系统&#xff0c;它的最大的特性就是可以实时的处理大量数据以满足各种需求场景&a…...

【python】编程题小代码

空心题&#xff08;平行四边形&#xff09; layer int(input("请输入你要打印的行数:")) for i in range(1,layer // 2 2): space_num layer - i for j in range(0,space_num): print(" ",end "") star_num 2 * i - 1 for j in range(0,sta…...

抖音小程序开发全攻略:如何规划项目和选择合适的开发团队

在数字化时代&#xff0c;抖音小程序成为企业推广和服务的重要渠道。本文将为您提供抖音小程序开发的全面攻略&#xff0c;重点介绍如何规划项目和选择合适的开发团队&#xff0c;并附有一些关键的技术代码示例。 1. 项目规划 在开始抖音小程序开发之前&#xff0c;详细的项…...

PSP - 蛋白质复合物结构预测 模版配对(Template Pair) 逻辑的特征分析

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/134328447 在 蛋白质复合物结构预测 的过程中&#xff0c;模版 (Template) 起到重要作用&#xff0c;提供预测结果的关于三维结构的先验信息&…...

喜报不断!箱讯平台获评2023年上海市促进现代航运服务业创新示范项目

近期&#xff0c;可谓捷报频传&#xff01;在箱讯科技子公司苏州箱讯获评苏州市软件和信息服务业 “头雁”培育企业没过多久&#xff0c;就又迎来好消息&#xff01; 日前&#xff0c;上海市交通委发布“2023年上海市促进现代航运服务业创新项目”评选结果&#xff0c;箱讯An…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...