【Linux】第二十七站:内存管理与文件页缓冲区

文章目录

  • 一、物理内存和磁盘交换数据的最小单位
  • 二、操作系统如何管理内存
  • 三、文件的页缓冲区
  • 四、基数树or基数(字典树)
  • 五、总结

一、物理内存和磁盘交换数据的最小单位

image-20231204201348600

我们知道系统当中除了进程管理、文件管理以外,还有内存管理

内存的本质就是对数据的一种临时存取,所以我们可以把内存看作一个非常大的缓冲区就可以了。

当内存需要数据的时候,可以直接从磁盘中读取,不需要的时候可以直接释放或者与磁盘进行交换

image-20231204202436014

为了方便物理内存与磁盘进行交互,我们会将物理内存看作一个一个的小格子,内存也是一种线性的。这个一个个的小单位是4KB

image-20231204202810807

像我们平时形成的可执行程序也是一个一个的以4KB为单位的小的数据段。

也就是说,如果一个可执行程序是4M,那么其实这个可执行程序也是4KB,4KB进行划分的。这是因为文件系统中数据块的大小就是4KB。

所以可执行程序在文件系统中天然就是每读一个块就是4KB

image-20231204203027361

而我们就将物理内存的这一个个4KB就叫做页框,将磁盘当中的这一个个4KB叫做页帧

image-20231204203413702

那么为什么必须是4KB,可以是1KB,2KB吗?

当然是可以的,不过这样我们需要修改操作系统的底层源代码。最终重新编译操作系统

而我们为什么要选择4KB呢,我们的文件压根可能就没有4KB。可能就是1KB,那么那3KB就浪费了。即便某个文件只有一个比特位,我们也不能只拿这1个比特位,必须将这4KB全部加载进来。

我们知道磁盘本身就是一个机械设备,注定了它IO时候访问的周期比较长,即比较慢,一次4KB很显然要比一次1KB效率要更高一些。(因为只需要磁头定位一次即可。比要定位四次快得多)

其次就是计算机中存在着局部性原理:在访问某些代码和数据时候,它附近的代码和数据也有很大概率被访问。而且因为机械运动才是慢的主要矛盾,有可能我们的文件只有100字节,但是我们也要读取4KB,这两个的效率其实差不多。而且100字节可能更加分散,需要更加精细

所以就有了基于局部性原理的预加载机制

  1. 它可以减少IO的次数,从而对系统整体进行提速 ----硬件

  2. 基于局部性原理,有了预加载机制 ----软件

注意这里的4KB是物理内存和磁盘交换数据的单位

二、操作系统如何管理内存

在操作系统层面上,要管理内存,肯定会用到虚拟地址。

而操作系统管理内存,也肯定是能看到内存的物理地址的。

那么操作系统如何管理内存呢??

先描述后组织

所以在操作系统里面肯定有一个东西

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

​ 像我们的系统如果有4GB的内存的话,那么最终会存在1024*1024*\1024*4 /4/1024,即约100万多个页。

然后我们在操作系统内核里面直接定义

struct page mem_array[1048579]

所以我们发现对内存的管理变为了对数组的管理。

即先描述后组织

而我们知道数组是天然有下标的,所以我们就天然的有了页号的概念

所以以后当有了一个地址以后,我们就可以知道它是在哪一个页号上的

因为4KB,需要用12位

所以我们只需要将这个低12位全部清零即可

比如0x11223344,我们直接让他按位与上0xFFFFF000

所以它最终的页号就是0x11223000

所以我们就直接用这个页号就找到了对应的属性

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

在我们系统中,所有申请内存的动作,都是在访问内存Page数组

而且这个Page结构体不会很大,因为会有一个Page类型的数组,它最终也是要在内存中存放着的,所以它不能太大,所以这也再次说明了前面的页框大小不能太小,因为它越小,这个数组就越大,占据的内存空间越大。

如下所示,它的page里面都是一些union,这个flags代表它的使用状态。(每一个比特位都有它的含义,比如当我要使用这个页框的时候,我们只需要判断其中的一个标志位是否为0,如果为0那么改为1,这个内存就被使用了)。下面的这个count代表的就是引用计数。用来判断该内存被多少人使用。

image-20231204212533812

同时在这个Page中还有一个lru,它是最近最少使用。也就是说操作系统会将最近最少使用的东西拿出来给刷新出去。

image-20231204213014901

三、文件的页缓冲区

如下图所示

在我们开机的时候,不仅仅是为我们创建了进程了,内存管理做好了等等。

还会将我们文件系统相关的数据都已经预加载到内存了,尤其是Super Block等这些文件系统相关的信息

image-20231205154712705

我们可能会说,那在操作系统上存在着很多分区,这也无所谓,因为可以用链表将他们组织起来

image-20231205155052716


如下是一个操作系统,里面有进程、files_struct等内核数据结构

image-20231205155603366

所以最终操作系统上层用的都是fd文件描述符

当我们在打开文件的时候,我们必须知道这个文件的路径+文件名,然后我们就能读取当前目录的数据块,从而找到文件的inode

因为这些inode Bitmap,Block Bitmap已经被提前加载到内存中了。然后我们确认这个inode是否存在,如果存在,直接将这个inode给加载进来,最后也就能读取到对应的数据块了。

以上都是一个文件被加载到内存当中的过程。

而现在我们关心的是这两件东西:文件的属性+文件的内容

所以我们需要做的就是,文件的属性如何被拿到。

我们知道文件的属性都在inode里面,struct file里面也有文件的属性,不过只有少量的属性。

所以我们会创建一个内核数据结构,struct inode,然后直接将磁盘中的inode里面的内容填写到这个内核数据结构中。而这个struct file是可以找到struct inode的

image-20231205161404122

可是我们之前说过,我们在上层调用fprintf以后,就会通过这个fd,往对应进程中找到对应的文件描述符,从而去找到struct file结构体。那么在这里如何将数据写到磁盘中呢?

我们现在只能去找到文件的属性

其实在struct file里面还存在一个结构叫做address_space。

image-20231205162743341

而radix_tree_root它是一颗多叉树

它结点里面是这样的结构

image-20231205172031647

如下图所示,它的每一个叶子结点都指向一个struct page对象,而这样的每一个struct page对象都对应着4KB的内存大小

image-20231205172537588

所以说当我们将数据拷贝到struct file以后,就会找到address_space,然后一路找到这棵树的叶子节点中,最终通过这个叶子节点的struct page去管理对应的内存

而上面这个就是文件的页缓冲区

四、基数树or基数(字典树)

在Linux中,我们的每一个进程,打开的每一个文件都要有自己的inode属性和自己的文件页缓冲区

什么是字典树呢?

类似于下面的26叉树每个结点可以指向26个字母

image-20231205174034476

我们可以用下面这个3个字母简单的来代替

image-20231205174230362

当我们要查找某个对象的时候,我们可以用bbb来作为key值,从而找到某个对象

image-20231205174428285

文件的内容按照4kb是有偏移量的

比如一个10MB的文件,它占据的内存就是10*1024*1024

而文件的内容是按照4KB一块一块的进行存储着的

image-20231205175531801

而这刚好就是2560块

所以我们就可以给他进行编号[1,2560]

而每一块乘以4KB就是他们的相对于原始数据的偏移量

所以前面的这一批数字[1,2560]它刚好每一个编号都是一个int类型的

而int类型是占据32位的

比如有一个数据是0xFF FF FF FF

这个整数我们可以将第一个数字看作一个b,第二个数字看作一个c,第三个数字看作一个a

如果我们可以像前面那样构建出一颗字典树

我们就可以利用这个文件的内容所在的区域

就可以利用字典树,找到对应的page的映射关系。


所以当我们进行读写文件的时候,从开头读,每一个读写都有偏移量。

根据这个偏移量,就可以将这个偏移量转化为树中的某一个page

这样我们就可以根据它的page偏移量,就确定先刷新哪一个page,后刷新哪一个page,就可以让文件有序的进行刷新了

最终我们的数据就成功的写入到了内存中

当我们将数据写入到了内存中以后,后序数据从内存如何写入到磁盘,就不是操作系统需要关心的事情了,这就导致了当我们突然断电以后,内存里面的数据都无法保存起来

上面的这个从内存刷新到磁盘当中的过程就是驱动层的事情了, 需要IO子系统来进行完成

五、总结

总之上面的过程其实就是下面的这张图

也就是说,操作系统里面也有一个文件缓冲区,最后它会被刷新到磁盘上去

image-20231205183319960

上面的过程,我们就把打开文件和文件系统的文件 产生关联了!

我们也可以发现,这里一共要经历三次拷贝,第一次将数据写入到C语言缓冲区中,第二次将数据从C语言缓冲区写入到文件缓冲区中,第三次是写在磁盘当中去

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/233279.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】面试OJ题———栈|队列|互相实现|循环队列|括号匹配

目录 1. 有效的括号 思路: 2.用队列实现栈 思路: 3.用栈实现队列 思路: 4.设计循环队列 思路: 1. 有效的括号 20. 有效的括号 - 力扣(LeetCode) 给定一个只包括 (,),{&…

Gazebo 跟踪8字形和U形轨迹(1) — 错误处理

Gazebo 跟踪8字形和U形轨迹(1) — 错误处理 整个过程还是比较曲折的,主要都是一些细小的问题,跑了很多遍模型才发现 参考轨迹生成问题不大,主要是参考横摆角和参考曲率部分有问题 atan和atan2 首先看下两者的区别 atan 函数:…

Electron[4] Electron最简单的打包实践

1 背景 前面三篇已经完成通过Electron搭建的最简单的HelloWorld应用了,虽然这个应用还没添加任何实质的功能,但是用来作为打包的案例,足矣。下面再分享下通过Electron-forge来将应用打包成安装包。 2 依赖 在Electron[2] Electron使用准备…

CF1898C Colorful Grid(构造)

题目链接 题目大意 n 行 m 列 的一个矩阵,每行有m - 1条边,每列有 n - 1 条边。 问一共走 k 条边,能不能从 (1, 1),走到(n, m),要求该路径上&am…

pandas数据处理闯关

pandas数据处理 第1关数据准备:将txt文件转成Excel文件第1关:将超市销售Excel文件根据商品的类别筛选存储任务描述相关知识:1. pd.read_excel()读取Excel文件2. DataFrame.to_excel() 向excel文件写入数据3. unique()唯一值函数4. 使用 loc 和 iloc 选择数据 本关代码 第2关数据…

基于YOLOv8深度学习的舰船目标分类检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

如何优雅地使用Mybatis逆向工程生成类

文/朱季谦 1.环境&#xff1a;SpringBoot 2.在pom.xml文件里引入相关依赖&#xff1a; 1 <plugin>2 <groupId>org.mybatis.generator</groupId>3 <artifactId>mybatis-generator-maven-plugin</artifactId>4 <version>1.3.6<…

【小沐学Python】Python实现WebUI网页图表(gradio)

文章目录 1、简介2、安装3、基本测试3.1 入门代码3.2 组件属性3.3 多个输入和输出组件3.4 图像示例3.5 聊天机器人3.6 模块&#xff1a;更灵活、更可控3.7 进度条 结语 1、简介 https://www.gradio.app/ Gradio是用友好的网络界面演示机器学习模型的最快方法&#xff0c;因此…

自然语言处理第2天:自然语言处理词语编码

​ ☁️主页 Nowl &#x1f525;专栏 《自然语言处理》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​​ 文章目录 一、自然语言处理介绍二、常见的词编码方式1.one-hot介绍缺点 2.词嵌入介绍说明 三、代码演示四、结语 一、自然语言处理介绍 自然语言处理&#xf…

04-详解Eureka注册中心的作用,具体配置,服务注册和服务发现

Eureka注册中心的作用 Eureka架构 远程调用的两个问题 服务的ip地址和端口号写死: 生产环境中服务的地址可能会随时发生变化,如果写死每次都需要重新修改代码多实例问题: 在高并发的情况下一个服务可以有多个实例形成一个集群,此时如果采用硬编码的方式只能访问服务的一个实…

【代码随想录】算法训练计划41

dp 1、343. 整数拆分 题目&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 输入: n 10 输出: 36 解释: 10 3 3 4, 3 3 4 36。 思路…

揭秘字符串的奥秘:探索String类的深层含义与源码解读

文章目录 一、导论1.1 引言&#xff1a;字符串在编程中的重要性1.2 目的&#xff1a;深入了解String类的内部机制 二、String类的设计哲学2.1 设计原则&#xff1a;为什么String类如此重要&#xff1f;2.2 字符串池的概念与作用 三、String类源码解析3.1 成员变量3.2 构造函数3…

【小聆送书第二期】人工智能时代之AIGC重塑教育

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;正文&#x1f4dd;活动参与规则 参与活动方式文末详见。 &#x1f4cb;正文 AI正迅猛地…

ubuntu 20.04 server 安装 zabbix

ubuntu 20.04 server 安装 zabbix 参考文档 zabbix没用过&#xff0c;用过prometheus&#xff0c; 因为现在很多应用都支持直接接入prometheus监控&#xff0c; 而且大部分语言都都有sdk支持&#xff0c; 可以直接接入自己的业务数据监控。 https://www.zabbix.com/cn/downlo…

激光打标机在智能手表上的应用:科技与时尚的完美结合

随着科技的飞速发展&#xff0c;智能手表已经成为我们日常生活中不可或缺的智能设备。而在智能手表制造中&#xff0c;激光打标机扮演着至关重要的角色。本文将详细介绍激光打标机在智能手表制造中的应用&#xff0c;以及其带来的优势和影响。 ​ 一、激光打标机在智能手表制…

MySql-substring函数和substring_index函数的使用及练习

目录 13.2.1 substring函数 1. 概述 2. 使用格式 3. 参数列表 4. 实例练习 13.2.2 substring_index函数 1. 概述 2. 格式 3. 参数说明 4. 返回值 5. 实例练习1 6. 实例练习2 13.3 牛客练习题 13.2.1 substring函数 1. 概述 substring函数是文本处理函数&#xf…

C语言 占位符 + 转义字符 + ASCLL 表 + 缓冲区

整型 占位符 取值范围 浮点型 占位符 转义字符 注意&#xff1a;绿色字体标注的为不可打印字符。 printf 常用占位符&#xff1a; printf 附加格式 ASCII 表 标准ASCII码的范围是0&#xff5e;127&#xff0c;只需7位二进制数即可表示。 缓冲区 缓冲区分类&#xff1a; sizeof(…

【数据结构】——排序篇(中)

前面我们已经了解了几大排序了&#xff0c;那么我们今天就来再了解一下剩下的快速排序法&#xff0c;这是一种非常经典的方法&#xff0c;时间复杂度是N*logN。 快速排序法&#xff1a; 基本思想为&#xff1a;任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码…

自动驾驶学习笔记(十六)——目标跟踪

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo 社区开发者圆桌会》免费报名—>传送门 文章目录 前言 匹配关联 轨迹记录 状态预测 总结 前…

C++使用策略模式,减少使用switch...case...

目录 原理函数类模板函数使用switch...case...不使用switch...case... 知识点decltypestd::remove_reference 原理 函数 #include <iostream> #include <functional> #include <map>void fun1(int a, int b) {std::cout << "fun1 : a "<…
最新文章