2024年最新Linux 10分钟让你掌握虚拟地址--写时拷贝技术_物理地址间拷贝(1),2024年最新熬夜肝完这份Framework笔记

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


执行后:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021030911222540.png)  
 不难发现,我们的父进程与子进程输出的变量都是同一个变量gval,值都为1。  
 但是我们在子进程中修改gval的值再让父进程执行,看他们的值会不会一样,并且再打印他们变量的地址。



#include <stdio.h>
#include <unistd.h>

int gval = 1;
int main()
{
pid_t pid = 0;

  pid = fork();
  if (pid == 0)//子进程
  {
  	  gval= 100;
      printf("child gval:%d,&gavl-%p \n", gval,&gval);
  }
  else if (pid > 0)
  {
  	  sleep(3);
      printf("parent gval:%d,&gavl-%p \n", gval,&gval);
  }
  return 0;

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/2021030912172176.png)


我们都知道,只要地址相同,数据一定也是相同的,一块内存数据不可能存在两个值。但是上面的结果却是地址相同,打印的数据不同。这是不是出错了呢?


实际上进程中访问的地址都是虚拟地址,而我们所说的程序地址空间实际上就是一个进程的虚拟地址空间。


**虚拟地址空间**是进程的虚拟地址空间,是操作系统为每个进程对于内存空间的虚拟描述,在linux下是一个结构体`mm_struct`


虚拟地址空间–操作系统为一个进程描述的虚拟的、连续的、完整的、线性的地址空间


而为什么不让进程直接去访问物理内存呢?  
 1、进程中代码数据的使用都是连续的地址,若直接使用连续的物理内存会造成内存的浪费  
 2、如果一个进程中存在一个野指针,会访问到另一个进程中的数据。直接访问物理内存会因为缺乏内存访问控制导致进程的不安全


物理地址是我们用户看不到的,我们所看到的地址`0x601044`就是一个虚拟地址,但是我们真正存放的那个数据是存放到物理内存当中的。那我们如何通过虚拟地址访问到对应的物理地址呢?–页表,通过虚拟地址映射到页表中,再通过映射到页表中的位置再映射到物理内存中,从而找到相对应的数据。


**页表功能**:保存了虚拟地址和物理地址之间的映射关系,提供内存访问控制


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210309120000724.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 虽然父子进程的虚拟内存地址是一样的,但是他们在物理内存存放的数据的地址是不一样的。通过各自的虚拟地址和页表,映射到不同的物理内存中,从而找到各自的数据


**作用**:进程使用虚拟内存,通过页表映射物理内存,可以实现进程中数据在物理内存上的离散存储。这样子大大提高了内存的利用率。在页表中可以直接对某个地址设置访问**权限标志位**,让这个地址成为只读,从而实现对内存的访问控制,让进程更加安全,提高了进程的独立性,保证了各个进程的稳定性。从而避免了进程在物理内存上存在的问题


### 写时拷贝


但是我们要知道一个问题,子进程在复制父进程的时候也复制了父进程的页表,那页表相同,虚拟内存地址也相同,映射的物理地址为什么不同呢?  
 **解**:Linux下的fork()函数利用了写时拷贝技术,子进程复制了父进程的页表,进程“读”操作的时候也能访问到同一个数据,那是因为他们映射到的物理内存上都是一块相同的空间。但是当有一个进程要进行“写”操作时,系统会在物理内存中复制出一块内存,然后将数据写进去,进行“写”操作的进程通过虚拟地址访问时就不是访问之前的那个数据,而是访问进行“写”操作后复制过来并写入数据的那块数据----写时拷贝技术:两个进程一开始指向同一块空间,等有进程进行“写”操作时候,再给进行“写”操作的进程重新开辟空间,目的就是提高子进程创建效率,保证进程的独立性


父进程创建子进程,子进程复制父进程的信息都是可读的,父子进程访问的都是同一块物理内存,只有当有进程进行写操作时,才会给子进程开辟新的内存空间来保存数据这也保证了进程之间的独立性。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210311095956201.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)


页表如何实现通过虚拟地址访问物理地址—MMU  
 **内存管理方式**:分页式内存管理 / 分段式内存管理 / 段页式内存管理


##### 分页式内存管理


分页式内存管理的虚拟地址组成:`页号` + `页内偏移`  
 页号:页表中表项的编号  
 页内偏移:具体一个变量首地址相较于内存起始位置的偏移量  
 虚拟地址通过页号找到页表中相对应的页号,再用页表内的页号对应的块号再映射到物理地址中的块号,然后再用虚拟地址的页内偏移找到唯一的物理地址  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210310121935657.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDQzOTg2,size_16,color_FFFFFF,t_70)  
 优点:将物理内存块进行分块管理,通过页表映射实现数据在物理内存上的离散式存储,提高内存的利用率  
 **公式**`物理内存块号 * 页面大小 + 虚拟地址偏移量 = 物理地址`


假设物理内存大小为4G,页的大小为4096字节,页数为4G / 4096 = 2^20,意味着页号占了虚拟地址的高20位,低12位就是页内偏移。


[用虚拟地址(逻辑地址)计算物理地址(十进制 & 十六进制)](https://bbs.csdn.net/topics/618668825)


##### 分段式内存管理



![img](https://img-blog.csdnimg.cn/img_convert/acd508bb7508d56ae1272a33062cbf69.png)
![img](https://img-blog.csdnimg.cn/img_convert/0f71254b91cbe6f47f421e90b6526d18.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值