文章目录
程序地址空间应该叫做进程地址空间!!!这一节我们主要引入进程地址空间概念,建立起宏观的认知。这个不属于语言,而是属于进程范畴!!!
1.C、C++内存空间布局验证

这个图不是物理内存!!!是进程地址空间,也叫做虚拟地址空间
2.一个例子,引入虚拟地址


我们可以看到,都是一样的,当我们修改代码,如下:


我们可以看到,g_val的地址还是一样的,但是在父子进程中的g_val值却不一样了!!!
我们知道进程是具有独立性的,即便是父子进程。
Q:但是同一个地址,为什么会有两种不同值呢?
A:我们不知道为什么,==但是可以肯定的是这个地址100%不是物理地址!!!这个地址我们叫做虚拟地址!!!==我们之前所学的所有地址都是虚拟地址,我们看不到物理地址!!!
3.虚拟地址
虚拟地址空间是虚的,不存在的,只是对物理地址进行抽象化、逻辑化。物理地址和虚拟地址是一一映射的。



4.理解空间划分

虚拟地址空间,本质其实是一个结构体:struct mm_struct

对于0-3GB的用户空间,程序员可以直接用地址来访问,但是要访问那1GB的内核空间,必须要经过系统调用!!!创建子进程,以父进程为模版,虚拟地址空间、页表也要拷贝给子进程。
Q:所以:如何理解进程是独立的?
A:进程=内核数据结构(task_struct、mm_struct、页表)+ 进程的代码和数据。当父进程或者子进程要修改一个数据时,会发生写时拷贝,会进行数据层面的分离!!!
结论1:定义全局变量,为什么全局有效?-》属于已初始化/未初始化数据区,只要地址空间存在,那么全局变量就会存在,所以全局变量会一直存在,包括static修饰的静态变量。
结论2:定义的字符串常量,其实和代码是编译在一起的,都是只读的(因为代码段就是只读的)
我们看一下下面两个代码:①char* a = "abcde",a这个字符串是常量字符串,不可以进行修改,但是编译不会报错,只会在执行的时候报错,页表里会有权限的东西,在检查时发现是只读的就报错了。②const char* b = "abced",明确在编译时就会报错,const修饰表明明确禁止通过指针 a 修改指向的内容,const约束的是编译器。推荐第二种写法。

结论3:命令行参数和环境变量属于父进程的地址空间内的数据资源,和代码区一样子进程会继承父进程的地址空间。所以,子进程也可以看到命令行参数和环境变量!!!
5.为什么要有虚拟地址?
这个问题也就是直接操作物理内存会造成什么问题?
理由1:因为有了虚拟地址,就必须转换为物理地址。要访问内存,必须先进行转换。(计算机中的任何问题,都可以通过新增一层软件层来解决)在虚拟到物理转换的时候,进行安全审核!!!变相的保证了物理内存的安全,维护进程的独立特性。
理由2:无序变有序

理由3:就是如上图的,进程管理和内存管理进行解耦合
Q:

A:vm_area_struct

堆区里面可以划分出很多的vm_area_struct。