&变量 得到的是真实的物理地址吗
下图中为什么地址一样,值不一样:
推断:
该地址,绝对不是物理地址,而是虚拟地址(线性地址)
因为如果物理地址相同,值不可能不一样
综上, &变量 得到的不是真实的物理地址,&变量得到的只是页表上与真实地址空间映射的值, 我们无法得知真实物理地址。
操作系统如何管理空间分配
先描述,再组织(mm_struct)
让每一个进程都认为自己是独占系统物理内存大小,进程彼此之间不知道,不关心对方存在,从而实现一定程度隔离
所谓进程虚拟地址空间,本质是内核的数据结构对象struct mm_struct(类似PCB),mm_struct是task_struct成员
mm_struct规定了task_struct的total-mm,stack_mm,global_mm等起始位置
页表将mm_struct中地址与真实物理地址对应
mm_struct+页表=linux虚拟内存管理方案
创建子进程时的mm_struct & 写时拷贝
子进程的mm_struct以父进程为模板
页表的虚拟地址部分与父进程完全一样,默认映射关系也一样(对应真实物理空间也一样),当父子进程都不对变量进行改变,映射关系依然不变。当父子进程任意一方要改变变量时,OS改变子进程的映射关系(虚拟地址不变,映射的实际地址改变),父进程映射关系不变。
这就是OS写时拷贝,只有写时才会重构子进程的虚拟地址和真实地址的映射关系,为子进程分配新空间
回到开始问题,当要修改gval变量时,OS启动写时拷贝,为子进程分配新空间,改变虚拟地址与真实空间映射。但虚拟地址不变。所以此时父子进程虚拟地址相同,但实际指向不同空间,所以改变自己的值也不会互相影响了
这保证了进程间的独立性,数据独立
变量名本质就是地址
进程=内核数据结构(task_struct & mm_struct)+自己的代码和数据
理解地址空间
地址本质就是一个数字,可以被保存在unsigned long中
空间区域划分
本质:只要有start & end即可
页表
页表是什么
可以理解为数据结构
类似unordered map
页表中有rwx & isexist
rwx 权限
页表中地址有权限信息(rwx)
char* str ="hello world"
*str ='H'
编译器不会报错
因为编译器无法识别,只有OS运行时才能检查
需要const可向编译器解释str只读特性
这就是为什么要有const,类似的,强制类型转换等也是这个道理
isexist
标记目标文件是否再内存中
支持分批加载/挂起等操作
支持延时开辟空间(不一定申请后立即使用,只要使用时开辟即可)
mm_struct初始化
程序在编译时,各个区域的大小信息已经有了
所以mm_struct可以方便初始化
OS可以根据exe中信息初始化进程信息
我们在程序中malloc等申请堆空间,其实只是虚拟内存中的堆区范围扩大(start&end),其实并没有真正开辟物理内存。可大大提高物理内存使用率(即开辟及用)
(虚拟)进程地址空间的作用
- 虚拟地址空间&页表:可以保护内存(防止野指针),可以驳回野指针
- 进程管理 和 内存管理 在系统层面进行解耦合。在初始化进程时可不申请内存
- 让进程以统一视角看待物理内存
物理内存&虚拟内存的rwx&分区
物理内存中不存在rwx概念,无权限概念, 只是经过页表控制产生了权限
数据可以被加载到物理内存任意位置处, 无分区概念
但经过页表映射后会产生栈区 堆区 代码区 (无序变有序), 会产生权限概念, 分区概念, 方便统一管理/组织
tips
所有内容都是OS自动完成
只要把进程管理好,地址空间就管理好了(task_struct包含mm_struct)
全局变量 字符常量 ---具有全局性,在程序运行期间都会有效