【Linux】深入理解进程(四)(进程地址空间)
文章目录
- 进程地址空间
- 虚拟地址
- 流程
- mm_struct
- 进程独立性
- 🚩页表和虚拟地址作用
进程地址空间

地址空间按此方式存储
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int g_val1;
int g_val2=1;
int main()
{printf("code:%p\n",main);const char* str="hello";printf("read only:%p\n",str);printf("%p\n",&g_val1);printf("%p\n",&g_val2);char* mem1=(char*)malloc(100);char* mem2=(char*)malloc(100);char* mem3=(char*)malloc(100);printf("heap:%p\n",mem1);printf("heap:%p\n",mem2);printf("heap:%p\n",mem3);printf("stack:%p\n",&str);static int a=1;int b=1;int c=1;printf("static:%p\n",&a);printf("stack:%p\n",&b);printf("stack:%p\n",&c);return 0;
}
code:0x4006dd
read only:0x400909
0x601060
0x601054
heap:0x74f010
heap:0x74f080
heap:0x74f0f0
stack:0x7fff479f3040
static:0x601058
stack:0x7fff479f303c
stack:0x7fff479f3038
验证了一个事,🚩static和全局变量存储在一个区,
问题来了:
int main()
{pid_t id=fork();if(id==0){printf("i am a child g_val:%d &g_val:%p\n",g_val,&g_val);}else if(id>0){g_val=200;printf("i am parent g_val:%d &g_val:%p\n",g_val,&g_val);}return 0;
}

相同的地址,值不同?
为什么?
虚拟地址
既然地址相同,值不同,说明这个地址绝对不是物理地址,我们叫做虚拟地址(线性地址)
我们平时写的C/C++使用的指针用的都是虚拟地址
🚩每个进程都有独立一张虚拟地址表
🚩CPUcr3寄存器(本质属于进程硬件上下文)页表指针管理这张虚拟地址表
流程

父进程先创建自己的页表,子进程复制父进程的页表,两者id虚拟地址相同,(代码共享,数据也共享),等到🚩访问任意一个id,物理内存就新开辟一块地址
所以两个id虚拟地址是相同的,但是实际物理内存是不同的
mm_struct
32位计算机有32根地址总线,每根地址总线传01信号,可以指定2^32个不同的内存地址
2^32*1byte=4GB
地址总线排列组合形成地址范围[0,2^32),在范围内,每个连续空间的每个最小单位都可以有自己的地址
进程地址空间:
描述进程可视范围的大小,是内核数据结构对象,存在于task_struct,里面要划分各种区域,start,end划出线性地址
进程地址空间也要被操作系统先描述再组织
总结:
🚩进程=内核数据结构(task_struct+mm_struct+页表)+程序的代码和数据
进程独立性
🚩进程被创建时,先创建内核数据结构再加载可执行程序
两个问题
1,怎么实现代码区和字符串常量区只读?
2,进程可以挂起?怎么知道代码是否在内存中呢?

页表第三列可设置权限,第4列可以知道代码是否加载到内存
,
此外,操作系统对大文件采用分批加载,(惰性加载),就是先只分配虚拟地址,不分配物理内存,这叫做缺页中断
🚩页表和虚拟地址作用
1,让进程以统一视角看待内存
2,避免直接接触物理内存,越界访问对物理内存造成损害,增加一个转换过程,可以拦截不合法请求
3,实现进程管理和内存解耦合
