linux系统编程之基础必备(五):Linux进程地址空间和虚拟内存

一、虚拟内存

先来看一张图(来自《Linux内核完全剖析》),如下:

分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~3,0具有最高特权级(内核),3则是最低特权级(用户),每当程序试图访问(权限又分为可读、可写和可执行)一个段时,当前特权级CPL就会与段的特权级进行比较,以确定是否有权限访问。每个特权级都有自己的程序栈,当程序从一个特权级切换到另一个特权级上执行时,堆栈段也随之改换到新级别的堆栈中。

段选择符:每个段都有一个段选择符。段描述符指明段的大小、访问权限和段的特权级、段类型以及段的第一个字节在线性地址空间中的位置(称为段的基地址)。而段选择符用于在描述符表中进行索引找到段描述符。

虚拟地址:虚拟地址的偏移量部分加上段的基地址上就可以定位段中某个字节的位置,即形成线性地址空间中的地址。

分页机制:当使用分页机制时,每个段被划分成页面(通常每页在4KB大小),页面会被存储于物理内存或硬盘上。如果禁用分页机制,那么线性地址空间就是物理地址空间。

当程序试图访问线性地址空间上的一个地址位置时,发生以下操作:

if(数据在物理内存中)
{
    虚拟地址转换成物理地址
    读数据
}
else
{
    if(数据在磁盘中)
    {
        if(物理内存还有空闲)
        {
            把数据从磁盘中读到物理内存
            虚拟地址转换成物理地址
            读数据
        }
        else
        {
            把物理内存中某页的数据存入磁盘
            把要读的数据从磁盘读到该页的物理内存中
            虚拟地址转换成物理地址
            读数据
        }
    }
    else
    {
        报错
    }
}

其中MMU负责虚拟地址到物理地址的转换工作,分段和分页操作都使用驻留在内存中的段表和页表来指定他们各自的交换信息。如果用户程序想要访问一个虚拟地址,经MMU检查无权访问(特权级),MMU产生一个异常,CPU从用户模式切换到特权模式,跳转到内核代码中执行异常服务程序,内核把这个异常解释为段错误,把引发异常的进程终止掉。

二、linux进程地址空间

由前面可得知,进程有4G的寻址空间,其中第一部分为“用户空间”,用来映射其整个进程空间(0x0000 0000-0xBFFF FFFF)即3G字节的虚拟地址;第二部分为“系统空间”,用来映射(0xC000 0000-0xFFFF FFFF)1G字节的虚拟地址。如下图

将其更加详细地展示如下:

程序路径:完整的绝对路径字符串如 “/home/simba/code/asm/simple”

环境变量:类似linux下的PATH,HOME等的环境变量,子进程会继承父进程的环境变量。

命令行参数:类似ls -l 中-l 就是命令行参数,而ls 就是可执行程序。

栈:就是堆栈,程序运行时需要在这里做数据运算,存储临时数据,开辟函数栈等。在Linux下,栈是高地址往低地址增长的。

对于函数栈来说,函数运行完毕就释放内存,举例递归来说,一直开辟向下函数栈,然后由下往上收复,所以递归太多层的话很可能造成栈溢出。

局部变量(不包含静态变量);局部可读变量(const)都分配在栈上。

共享库和mmap内存映射区:比如很多程序都会用到的printf,函数共享库 printf.o 固定在某个物理内存位置上,让许多进程映射共享。mmap是个系统函数,可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write函数。此外,调用malloc 时正常是调用brk 系统调用分配内存,特定条件下是调用mmap 来映射物理内存到进程地址空间。

堆:即malloc申请的内存,使用free释放,如果没有主动释放,在进程运行结束时也会被释放。

Text Segment: 可执行程序(二进制)(.text);全局初始化只读变量(const)(.rodata);字符串常量(.rodata);均在这里分配。

Data Segment: 全局变量(初始化的在.data,未初始化的在.bss);静态变量(全局和局部)(初始化的在.data,未初始化的在.bss);全局未初始化只读变量(.bss);均在这里分配。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Nian糕的私人厨房

jQuery 动态绑定

这是在项目过程中所遇到的一个问题,给 JS 动态生成的元素绑定事件失效,代码如下所示:

963
来自专栏美团技术团队

Vuex框架原理与源码分析

Vuex是一个专为Vue服务,用于管理页面数据状态、提供统一数据操作的生态系统。它集中于MVC模式中的Model层,规定所有的数据操作必须通过 action -...

5974
来自专栏PHP在线

YII运行原理

应用执行流程: 浏览器向服务器发送 Http Request | 控制器(protected/controllers) | |—> Action | 创建模型 ...

3196
来自专栏逆向技术

框架原理第三讲,RTTCreate,运行时类型创建.(以MFC框架讲解)

       框架原理第三讲,RTTCreate,运行时类型创建.(以MFC框架讲解) 通过昨天的讲解,我们已经理解了运行时类型识别是什么. 比如  CObje...

1976
来自专栏Play & Scala 技术分享

Play Scala 2.5.x - Play JSON开发指南

2825
来自专栏大内老A

.NET Core采用的全新配置系统[2]: 配置模型设计详解

在《.NET Core采用的全新配置系统[1]: 读取配置数据》中,我们通过实例的方式演示了几种典型的配置读取方式,其主要目的在于使读者朋友们从编程的角度对.N...

1709
来自专栏我是攻城师

Nodejs笔记(三)

3329
来自专栏程序员互动联盟

【专业技术】C++ RTTI及“反射”技术

RTTI   RTTI(Run-Time Type Information)运行时类型检查的英文缩写,它提供了运行时确定对象类型的方法。面向对象的编程语言,象C...

2995
来自专栏HTML5学堂

在对象的原型上添加方法?

HTML5学堂:利利前段时间写了几个数组、字符串的方法,其中有一个是克隆(复制)一个数组。于是,最近一直在琢磨如何让这个复制变得更简单,可不可以把这个自定义的方...

2825
来自专栏精讲JAVA

深入探索 Java 热部署

在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加...

611

扫码关注云+社区