分布
我们一般认为的内存分布:
两个注意
我们以前就知道,栈是向下增长的,堆是向上增长的
同时结合图上高低地址分配
会不会有一个疑问?
明明栈是向下增长的,为什么数组中首元素的地址反而是最小的呢?
换言之,为什么栈中的数组,结构体的结构是向上增长的?
因为数组在开辟空间的时候,会一次性开辟足够的空间,
然后将数组首元素放在空间最下面,
然后依次添加元素,
从而实现向上增长
除此之外,还有一点需要注意:
在c语言中,一个字符串常量往往是不允许被修改的
为什么?
因为字符常量区在初始化数据区域里,
同时与正文代码紧紧相邻,
字符常量区被编到代码区,
众所周知,代码是不可被写入的,
所以字符串常量不可被修改
物理地址与虚拟地址
先看一段代码
从运行结果可以看出,
父子进程的tmp拥有相同的地址,
但是,
值却不同???
所以我们可以得出一个结论:
这并不是真正的物理地址,可能只是一段虚拟地址!!!
虚拟地址与物理地址的联系
本质是一种映射关系!
os为每一个进程准备一个页表和一个虚拟地址空间``,
在访问物理地址时,会先在页表映射,
如果访问的是非法地址,
则会阻止你的访问!!!
那么为什么一个地址会有两个值
首先,子进程的虚拟地址空间与页表都是继承父进程的,
所以页表映射的物理地址是相同的,
但是,如果有一方需要更改变量的值,
os会为那一方重新开辟一份物理地址,
并且修改页表的映射关系,
虽然此时的虚拟地址是相同的,
物理地址却不同了,也就出现了地址相同,值却不同的现象。
这个过程也可以叫做写时拷贝
页表的结构与作用
页表不仅仅有映射关系,
还有对应物理空间的读写权限
上面我们提到过,字符串常量是不可被修改的,
因为字符常量区被编到代码区了,
所以,代码区与字符常量区显然在页表不具有写权限
所以页表可以起到保护物理内存的作用!
这是页表的第一个作用
第二个作用
无需变有序
在内存中的数据是无序的,
但是,虚拟地址却有一套地址空间,
那么显而易见,
页表在映射时顺带将不同数据类型的数据分类,
才让数据变得有序起来
为什么要存在地址空间?
有效的保护了物理内存
非法的访问与映射,os都会识别并组织,
地址空间与页表都由os进行管理,'
所有访问都在os监管之下
使OS的耦合度更低
因为地址空间与页表的存在,
物理内存可以不对数据类型进行分类管理,
可以直接进行加载,
物理内存的分配与进程的管理就可以分开,
内存管理模块与进程管理模块就完成了解耦合的操作
保证进程的独立性
因为地址空间的存在,
每一个进程都会认为有4GB的空间可以使用,
并且各个区域都是有序的,可以通过页表映射不同区域,
实现进程的独立性,
同时,进程之间并不知道也不需要知道其他进程的存在