1、程序地址空间分布
高地址 进程地址空间
内核空间(用户代码无法访问)
环境变量
命令行参数
栈
共享区
堆
未初始化数据(数据段)(全局、静态数据)
初始化数据(数据段)
字符常量区(代码段)(可执行代码、只读常量)
低地址 代码区(代码段)
- 栈,又叫堆栈,放的是非静态局部变量、函数参数、返回值等,栈是向下增长的,且栈是一段线性空间,遵从先进后出的规则,小内存,自动化,可能会溢出。我们通常会在函数栈帧中创建很多变量,我们称这个变量具有临时性,这个变量即为局部变量,存于栈上。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库,用户可以使用系统接口创建共享内存,作进程间通(后面学到通信的时候会讲到) 。
- 堆用于程序运行时动态内存分配,我们的手动开辟空间都是在这一部分上的。堆是向上增长的,是一段非连续的空间,特点是大内存,手工分配管理、申请的大小是随意的,但是可能会导致内存泄漏问题。
- 在堆区上开辟空间后会返回一个指针,这个指针是指向堆区上开辟的内存块的,其中存放的是从堆区上开辟的空间,但是这个指针本身是在函数中定义的,因此属于一个局部变量,存在栈上。
- 数据段存储的是全局数据和静态数据。
- 代码段存放的是可执行的代码、只读常量。
- 数据段和代码段属于编译时编译器分配的空间(静态存储区域),其他的属于运行时系统分配的空间(动态存储区域)。
- 内核空间用户后面会讲到。
- 命令行参数和环境变量:命令行参数指的是在命令行上敲入的一些参数,main函数的第二个参数就是负责获取命令行参数的,比如选项和命令等
- 环境变量:main函数的第三个函数就是负责接收环境变量的,在上篇文章(环境变量)中已经着重进行讲解。
2、虚拟地址空间
我们在C/C++中看到的所有的地址都是虚拟地址,物理地址用户一概看不到,是由操作系统统一管理的。
在每一个进程建立的时候,操作系统不仅会为进程创建一个PCB,同时还会为每一个进程创建一个进程地址空间,即每一个进程都会有自己独立的进程地址空间。
3、进程地址空间存在的意义
- 保护内存:如果没有进程地址空间,那么就是task_struct直接对物理地址进行访问,那么如果有时出现代码写错,出现访问越界,或者野指针,或者指针指向操作系统的代码,那么当我们修改的时候,就会对其他代码造成影响,同时也会会导致物理内存的利用率低下,且访问控制薄弱。
- 实现功能模块的解耦:当我们向系统申请一块空间,比如使用malloc函数来申请空间的时候,系统不会马上去实际的物理内存中申请,只会在进程地址空间中的堆区上将对应的区域放大,当系统检测到此时需要访问到那块内存的时候,系统才会马上向内存申请对应空间,这样就大大地增大了内存资源的利用率。
- 简化进程的设计与实现:程序编译时确定的地址都是虚拟地址,但是访问的时候操作系统会将这个虚拟地址在页表中映射得到物理内存地址,进而访问物理内存区域,这样的话,每个进程都有自己独立的虚拟地址,跟其他进程互不影响,但是数据可以在物理内存任意位置存储,因为可以通过页表映射访问到实际物理存储的位置,实现了数据在物理内存上的离散存储,提高了内存利用率,并且可以在页表中对地址访问加以权限访问,提高了内存访问控制,程序运行时,其中中的数据和指令被打散在物理内存中存储,同时在页表中记录对应数据虚拟地址和物理地址的映射关系,以便于进程在虚拟地址访问的时候,操作系统能够通过映射找到物理地址进而访问物理内存。
979

被折叠的 条评论
为什么被折叠?



