大家好呀,我是残念,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流哦
本文由:残念ing原创CSDN首发,如需要转载请通知
个人主页:残念ing-CSDN博客,欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:[残念ing 的【Linux】系列专栏——CSDN博客]
目录
- 先看一个现象
- 1 进程地址空间
- 1.1 理解地址空间
- 1.2 理解区域划分
- 1.3 理解地址空间上的地址
- 2 虚拟地址(进程地址)的运用全过程
- 2.1 不进行数据修改时
- 2.2 进行数据修改后(写时拷贝)
- 3 知识点补充(了解)
- 3.1 关于页表
- 3.2 关于地址空间mm_struct
- 4 为什么要有进程地址空间(虚拟地址空间)
- 4.1 为什么遇到野指针程序就崩溃了?
- 5 总结:
学习目标:
1 进程地址空间
2 虚拟地址(进程地址)的运用全过程
3 知识点补充(了解)
4 为什么要有进程地址空间(虚拟地址空间)
5 总结
先看一个现象
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int gval = 100;
int main()
{printf("我是一个进程,pid:%d,ppid:%d\n",getpid(),getppid());pid t id = fork();if(id == 0){while(1){// childwhile(1)printf("我是子进程,pid : %d, ppid : %d, gval: %d, &gval: %p\n",getpid(),getppid(),gval, &gval);gval++;sleep(1);}}else{//parentwhile(1){printf("我是父进程,pid : %d, ppid : %d, gval: %d, &gval: %p\n",getpid(),getppid(),gval, &gval);sleep(1);}}}
我们发现gval的地址空间都是一样的,我们要知道的是整个地址一定不是物理地址,通过这个现象我们就要引出虚拟地址(线性地址)
1 进程地址空间
1.1 理解地址空间
目的:让每一个进程都认为自己是独占系统物理内存大小的,进程彼此之间不知道,不关心对方的存在,从而实现一点程度的隔离
所谓进程虚拟地址,其实本质上就是一个内核数据结构对象(类似PCB)
1.2 理解区域划分
本质就是:空间区域的划分,只需要知道开始和结束就可以。
1.3 理解地址空间上的地址
- 地址本质就是一个数字,可以被保存在usningned long(4字节)
- usning long total_vm 空间范围内的地址,我们可以随便用,暂时不需要记录它的地址
2 虚拟地址(进程地址)的运用全过程
虚拟地址+页表=虚拟内存管理方案
当建立了子进程后,子进程都是继承了父进程的地址空间结构和虚拟地址的,当在不修改数据和程序时,子进程的数据是浅拷贝了父进程的数据和代码,但是如果子进程修改了数据或着代码的话,那么物理地址会新开一个单独的空间给这个子进程,这个子进程的页表也会相应的改变。
2.1 不进行数据修改时
2.2 进行数据修改后(写时拷贝)
知识补充:
进程 = 内核数据结构(task_struct/mm_struct/页表)+ 自己的代码和数据
进程的独立性:内核数据结构各自一份、代码和数据也是独立的
3 知识点补充(了解)
3.1 关于页表
isexists:判断目标内容是否在内存中
作用:分批加载、挂起等操作
3.2 关于地址空间mm_struct
它是结构体变量,就必须初始化,这些初始化在可执行程序编译时,各个区域的大小信息就已经有了,这些都是从可执行程序来的。
4 为什么要有进程地址空间(虚拟地址空间)
1.虚拟地址空间+页表:保护内存
2.进程管理和内存管理在系统层面进行解耦合了
3 让进程以统一的视角看待物理内存,可执行程序和数据可以加载到物理内存的任意位置处。(将“无序”变“有序”)
4.1 为什么遇到野指针程序就崩溃了?
因为野指针运用到的地址不是物理地址,全都是虚拟地址,用户层是不可能看到物理地址的 ,看到的全都是虚拟地址,当指针指向的虚拟地址不对或与其他冲突时,对应的映射不对或者权限不对,操作系统就会杀掉这个进程。
5 总结:
地址空间的本质就是一个struct mm_struct ,里面所有的内容,都是OS系统自动完成的。我们只要把进程管理好了,地址空间就管理好了。比如:全局变量,字符串常量具有全局性,在程序运行期间都会有效,其实实际上是在地址空间中随着进程,一直存在,全局变量的虚拟地址也会一直被用户看到。