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

Linux : 进程地址空间

目录

一  前言

二 进程地址空间是什么

1.现象

2.虚拟地址空间

3. 现象解释 

4. 写时拷贝

三 为什么要存在进程地址空间

四 进程地址空间是如何实现的

1 操作系统如何管理进程地址空间


一  前言

进程地址空间图:

 

在学习C语言的内存管理的时候,我们看到过这样一张图:

😀:放的是非静态局部变量、函数参数、返回值等。 栈是向下增长的,且栈是一段线性空间,遵从先进后出的规则,小内存。我们通常会在函数栈帧中创建很多变量,我们称这个变量具有临时性,这个变量即为局部变量,存于栈上。且函数的递归意味着不停的创建局部变量,函数参数,返回值,而栈内存较小,所以函数的不停递归,会造成栈溢出。

😃:用于程序运行时动态内存分配,我们的手动开辟空间都是在这一部分上的。堆是向上增长的,特点是大内存,手工分配管理、申请的大小是随意的,但是(若不free)可能会导致内存泄漏问题。在堆区上开辟空间后会返回一个指针,这个指针是指向堆区上开辟的内存块的,其中存放的是从堆区上开辟的空间,但是这个指针本身是在函数中定义的,因此属于一个局部变量,存在栈上。

😄数据段:数据段存储的是全局变量和静态变量

😎代码段:是可执行的代码、只读常量。

😐命令行参数和环境变量:命令行参数指的是在命令行上敲入的一些参数,main函数的第二个参数就是负责获取命令行参数的。main函数的第三个函数就是负责接收环境变量的。


二 进程地址空间是什么

1. 现象

接下来我们先看一个例子:我们实现一个代码让父子进程打印同一代码段里的同一数据global_value

 运行结果:

我们发现在同一个地址空间ox60105c,父进程和子进程访问时获取的值却不是相同的 ,因此,我们可以先排除global_value的地址是物理地址(因为物理磁盘的同一个地址,只能存放唯一确定的一个值)。

2.虚拟地址空间

由上面的现象我们肯定能推断出这两份数据的地址一定不会是真实的物理地址(物理地址独一份),它是虚拟地址空间,所以我们在C/C++中看到的所有的地址都是虚拟地址。

  • ⏰在每一个进程建立的时候,操作系统不仅会为进程创建一个PCB,同时还会为每一个进程创建一个进程地址空间,即每一个进程都会有自己独立的进程地址空间,那么问题就来了,系统中那么多进程,这样系统中的进程地址空间就会非常多,那么操作系统就要对这些空间进行先描述再组织,于是系统就为进程地址空间创建了一个mm_struct,其中对虚拟地址的每个区域都进行了划分,每一个进程都是相对独立互不影响的,每一个进程的PCB和mm_struct都是相互独立的,这就是进程的独立性。

3. 现象解释 

父进程和子进程都有自己独立的进程地址空间,也有独立的页表结构。子进程由父进程创建,因此子进程的进程地址空间是拷贝父进程的进程地址空间。
一开始父子进程并未对进程地址空间做修改,因此global-value值在一开始是指向同一个物理内存。
后来,子进程修改了global-value的值,操作系统通过页表映射发现global-value的值是被两个进程共享的,就会发生写时拷贝(操作系统为了保持进程的独立性,当子进程或者父进程任何一方尝试对共享的数据做写入,操作系统就会在物理内存上重新开辟一块新的内存空间同时拷贝原来的数据,然后修改写入方的页表映射关系,使其指向新的物理地址,再进行写入操作。整个修改的过程中,这些工作与父子进程的虚拟地址没有关系,只有底层经过页表映射到了新的物理地址,因此我们观察到的虚拟地址是相同的,但是内容却不同)。

 当子进程继续执行代码, 修改了0x60104C地址所存储的值时, 操作系统就会在在物理空间中申请一个新的地址供子进程存储数据使用, 同时修改子进程页表内容

4. 写时拷贝

父子进程中的任意一方试图对共享数据进行写入,操作系统就会先将原数据进行拷贝,然后改变要写入一方的页表映射,使它映射到新的物理内存中,然后再让进程进行写入的技术称为写时拷贝。 


三 为什么要存在进程地址空间

  • 保证了数据的安全性;如果进程出现越界非法访问、非法写入等情况时,页表会对进程进行拦截。直接对物理内存进行访问,对于账号信息等数据是不安全的(可能会出现意外损坏数据或者恶意读取用户信息等问题)。
  • 方便进程之间数据代码的解耦,保证了进程的独立性;一个进程对数据的修改不会对另一个进程造成影响,保证了进程的独立性。
  • 让进程以统一的视角看待进程的代码和数据所在的各个区域,同时方便了编译器以统一视角编译代码。可执行程序在被编译器编译的时候,其代码和数据在内存中已经有虚拟地址了(这种地址在磁盘上被称为逻辑地址),也就是说操作系统和编译器都是遵守地址空间这一理论的。在程序被加载到内存成为进程前,每个变量/函数都具备了物理地址。因此,我们现在有两套地址,一套是用于表示物理内存中代码和数据的物理地址;另一套是用于程序内部函数之间进行跳转的虚拟地址。加载完毕后,代码的各个区域的地址,操作系统和编译器都已经知道了。进程被调度时,CPU拿到虚拟地址,经过地址空间的页表映射,就能查到物理地址,通过物理地址访问到代码,然后执行。CPU -> 虚拟地址 -> 页表 -> 物理地址 -> 执行。CPU运行的整个过程中,都没有见到物理地址,只通过虚拟地址就可以运行程序。

四 进程地址空间是如何实现的

1 操作系统如何管理进程地址空间

操作系统要为每一个进程分配地址空间,那么操作系统是否要管理这些地址空间呢?当然是要管理的。那么,操作系统如何管理进程的地址空间?说到管理,管理的方法是先描述,再组织。首先,进程本身就是需要被管理的,操作系统管理它的方式是将进程的信息存入结构体PCB(task_struct)中,再用链式结构将每一个进程的PCB对象组织起来。而地址空间也是通过内核数据结构mm_struct进行管理的,OS会为每一个进程创建一个mm_struct(结构体)对象进行管理。该结构体对象保存在它所对应进程的PCB中。(PCB中的一个属性mm_struct)

相关文章:

  • RBAC 权限系统管理模型 学习笔记
  • 笔记四:C语言中的文件和文件操作
  • 168. Excel 表列名称
  • vue左侧边框点击后让字体高亮
  • QTS单元测试框架
  • 多线程-CompletableFuture
  • 深度解析:视频软编码与硬编码的优劣对比
  • 【TCP/IP协议栈】【网络层】子网划分、子网掩码
  • 《从信息论视角:DataWorks平台下人工智能探寻最优数据编码的深度剖析》
  • 常见限流算法
  • Shell编程概述与Shell变量
  • 建筑兔零基础自学python记录39|实战词云可视化项目——章节分布10(上)
  • 【Flink银行反欺诈系统设计方案】4.Flink CEP 规则表刷新方式
  • Redis相关面试题
  • Mybatis集合嵌套查询,三级嵌套
  • JAVA与计算机网络基础
  • 生物信息学与计算生物学:各自概念、主要内容、区别与联系、发展展望?
  • 微服务的春天:基于Spring Boot的架构设计与实践
  • 如何把GUI做的像Web一样美观:Python PyQt6特性介绍,如何结合QSS美化
  • C++中`const` 和 `static` 关键字详解
  • 上海博物馆展览进校园,“小先生”传递文物知识
  • 高新波任西安电子科技大学校长
  • 讲座|消逝之钟:《红楼梦》与《布登勃洛克一家》中的时间观
  • 俄代表团:16日上午将继续“等候乌代表团”
  • 泽连斯基抵达安卡拉,称乌将派出最高级别代表团参与谈判
  • 向猫学习禅修之后,你会发现将生活降格为劳作是多么愚蠢