【Linux学习】进程地址空间

什么是进程地址空间
在这里插入图片描述
  如图,每个进程都会被分配一个独立的进程地址空间(也称虚拟地址空间),该空间内的地址并非内存上真正的物理地址,而是叫做虚拟地址,我们使用程序打印出来的所有地址均是虚拟地址,因为系统不会让我们直接访问到物理地址。虚拟地址会通过一个页表进行映射,对应到真实的物理地址上。

这样做的目的是什么?为了保护物理内存。进程看到的都是虚拟地址,它只能访问到物理内存中被映射的部分,不同的进程被映射的位置不同,如果它要越界到其他进程的空间,由于映射中找不到这样的映射关系,便会终止该操作。这样一来就不会访问到其他进程的内容(防止越界),于是真实的物理内存就这样被保护起来了。

  既然每个进程都会被分配一个地址空间,那么系统中必然存在多个地址空间,因此需要将其管理起来,管理的本质:先描述再组织。

  就像进程控制块使用task_struct结构体描述一样,地址空间同样用一个内核结构体:mm_struct来描述。组织方式则是在PCB中加入一个指向mm_struct的内存指针,将其与PCB绑定在一起进行组织。这里可以看下mm_struct中的内容:

struct mm_struct
{
      unsigned long code_start; //代码区
      unsigned long code_end;

      ...

      unsigned long heap_start;  //堆区
      unsigned long heap_end;

      unsigned long stack_start;  //栈区
      unsigned long stack_end;
}

一个进程的地址空间,内核区的在物理内存上只存在一份,所有进程的内核区映射到的是同一个位置,大家共享,用户区的映射则相互独立。

这里仅仅示意内核与用户区的映射区别,实际上用户区的映射往往是不连续的
另外,当进行创建子进程操作时,系统本着不浪费空间的原则,最开始父子进程映射的物理内存是相同的,直到某一方修改进程中的数据发生写时拷贝,二者的映射便会分开,实现进程独立。

结构体中定义了用户区内存分配的区域,也就是下面要提到的内存五大区域:

1.栈区——程序运行时编译器自动分配,程序结束时编译器自动释放。存放函数参数,局部变量等。
2.堆区——由程序员来分配和释放,存放的是使用malloc、new等创建的对象。
3.bss段——未初始化的全局变量与静态变量,以及初始化为0的全局/静态。
4.全局区——编译时分配内存,程序结束时系统自动释放,储存已初始化的全局与静态变量还有常量。
5.代码段——不可修改,存放函数体的二进制代码。

后三个都比较好理解,这里主要了解堆区与栈区的差别。
1.内存管理方式:栈由编译器自动管理,堆由程序员手动管理(这就可能导致内存泄漏)。
2.空间大小:栈空间较小,但分配的空间连续,不会产生空间碎片。堆空间较大,分配空间不连续,易产生空间碎片。
3.生长方向:栈由高地址向低地址生长,堆由低地址向高地址生长。
4.分配方式:栈既可以静态分配也能动态分配,但与堆不同的是动态分配后是可以自动释放的。堆只能动态分配。
5.分配效率:栈是底层直接支持的数据结构,因此效率远高于堆。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值