操作系统内存区域:
从低地址到高地址:
**代码区:**存储程序的二进制指令,即程序源码编译后的二进制代码
初始化数据:存储已被初始化的全局变量、常量
**未初始化数据:**存储未被初始化的全局变量,和初始化数据段一样都属于静态分配,在编译阶段就确定了大小,不释放
**堆区:**主要用于动态分配,C语言中malloc/new和free操作堆内存,( 由程序员分配释放,若不释放,程序结束时由操作系统回收)
**栈区:**主要用于函数调用时存储临时变量的,这部分的内存是自动分配,自动释放的

进程地址空间
创建一个子进程,让他们访问同一个变量,观察是否地址一样:

结果:地址和值都是一样的:

子进程更改变量的值:

结果:val变量的值不一样了,但是地址还是一样的:

思考:一个地址怎么可以同时代表两个变量呢?
结论:这个地址绝对不是物理内存地址,这个地址叫做虚地址。我们之前所用到的所有地址都是虚地址。
虚地址到物理地址的转换:
通过页表把虚地址转化为内存的物理地址:

地址空间也是一个结构体:
里面有各个区域的划分变量:

进程地址空间存在的意义:
1、把物理内存从无序看为了有序。
2、将进程管理和内存管理进行耦合
3、进程空间+页表,保证了内存安全的重要手段
4、在new开辟空间时,首先开辟好的是虚拟空间,如果要用这个空间才会去开辟物理空间,提高了资源利用率
写时拷贝。
子进程和父进程是公用一个代码的,他的PCB,地址空间,页表,也都是拷贝的父进程的,所以页表所对用变量的虚地址也是一样的,在变量只是只读的情况下,两个虚地址指向的是同一个物理内存,但是当子进程改变变量的时候就会发生写时拷贝:

思考:为什么要是写时拷贝呢,不能直接在子进程要修改的时候给他开辟一块一样的空白地址就行了吗,为什么还要把原来的值拷贝过来?
因为:不一要对原来的值全部修改,有时候只是修改部分,或者增加删除等。
进程地址空间工作图:
