【Linux进程七】程序地址空间

devtools/2025/3/29 3:35:50/

【Linux进程七】程序地址空间

  • 1.进程的地址空间分布
  • 2.类型的本质是偏移量
  • 3.什么是进程地址空间
  • 4.页表的映射和访问权限字段
  • 5.地址空间的作用

1.进程的地址空间分布

在这里插入图片描述
堆是向上扩展的,栈是向下扩展的
因为字符常量区和代码区相邻,受到同样的保护,字符常量区和代码区一样不允许修改
通过代码验证:
在这里插入图片描述
在这里插入图片描述

2.类型的本质是偏移量

栈整体向下扩展,局部向上读取
堆整体向上扩展,局部向下读取
用栈举例:
在这里插入图片描述

所以类型的本质是偏移量

3.什么是进程地址空间

我们用下面的代码可以查看到一个事实

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
#include<stdlib.h>    int main()    
{    int id = fork();    int tmp = 100;    if(id == 0)//子进程执行的代码    {    tmp = 200;    while(1)    {    printf("子进程tmp: %d,&tmp: %p\n",tmp,&tmp);    sleep(1);    }    }    if(id > 1)//父进程执行的代码    {    while(1)    {    printf("父进程tmp: %d,&tmp: %p\n",tmp,&tmp);    sleep(1);    }    }                                                                                                                                                                   return 0;    
}    

在这里插入图片描述

子进程和父进程的地址一样,但却有两个值

所以是事实:平时看见的地址并不是真实的地址而是虚拟地址,真实的地址空间被称为物理地址(物理内存)

在这里插入图片描述
每个进程都有自己的进程地址空间

操作系统想管理进程,就一定要先描述,再组织
所以进程地址空间是一个数据结构struct用于描述进程

在这里插入图片描述

程序地址空间有多个区域结合而成,而区域之间的划分就是区域开头begin和区域结尾end
说明进程地址空间就是一个线性区域
就像下面代码一样:

struct mm_struct
{int code_begin;//代码区起始int code_end;//代码区结束int init_begin;//初始化区起始int init_end;//初始化区结束int heap_begin;//堆区起始int heap_end;//堆区结束......
};

4.页表的映射和访问权限字段

OS为每一个进程配对一个虚拟地址空间和一张页表,要访问物理地址时,需要先在页表进行映射(若访问的是非法地址,则会在页表层阻止你的访问)

在这里插入图片描述
所以父进程和子进程之间的关系是这样的:
在这里插入图片描述

创建子进程,就要创建子进程的PCB,及地址空间和页表结构 子进程的相关内核数据结构的属性字段会继承父进程
正常来说,子进程要对tmp对修改,把tmp变成200,父进程通过映射关系找到tmp,读到200
但因为进程具有独立性,子进程对数据的修改,不影响父进程,所以当子进程要对tmp修改时,在内存中重新申请一块空间,拷贝tmp值给新空间,重新映射指向新开辟的空间,不影响父进程的tmp值,最终将新开辟的空间tmp值改成200
所以二者虚拟地址相同,但物理地址不同

更详细的页表:
在这里插入图片描述

常量字符串不能修改,正是因为映射时的访问权限字段里没有修改权限

5.地址空间的作用

  1. 让进程已统一的视角看待内存(物理地址):无序变有序
    任意一个进程都可以通过地址空间和页表将内存中乱序的内存数据变为有序
  2. 虚拟地址有效保护了物理地址
    操作系统通过虚拟地址的映射过程,用页表的权限访问字段阻止了非法访问
  3. 将进程管理和内存管理解耦
    因为有进程地址空间和页表的存在,物理内存的分配就可以和进程的管理互不打扰
  4. 保证进程的独立性
    操作系统通过虚拟地址的映射过程,用页表将进程映射到不同的物理内存,实现进程间的独立
    进程=内核数据结构+进程的代码和数据

http://www.ppmy.cn/devtools/168817.html

相关文章

umi自带的tailwindcss修改为手动安装

1》为什么改为手动&#xff1f; 主要是为了解决这个报错问题&#xff0c;虽然重新运行也可解决&#xff0c;但是总是要运行2-3次&#xff0c;比较麻烦 2》如何手动 1&#xff0c;先在devDependencies下安装这两个包 pnpm install postcss8.5.1 -D "autoprefixer"…

linux 部署node服务

安装nodejs ----------------------------------------------------------------- # 下载nodejs wget https://nodejs.org/dist/v22.14.0/node-v22.14.0-linux-x64.tar.xz # 移动到/opt/目录 mv node-v22.14.0-linux-x64.tar.xz /opt/ # 切换目录 cd /opt/ # 解压nodejs安…

Redis 底层数据结构源码剖析

一直好奇为什么 Redis 处理速度这么快&#xff0c;很大部分是因为数据结构设计的好&#xff0c;所以学习一下 Redis 数据结构的底层实现。 Redis 发展到现在已经有 9 种数据类型了&#xff0c;其中最基础、最常用的数据类型有 5 种&#xff0c;它们分别是&#xff1a;字符串类…

游戏立项时期随笔记录(1)

模拟经营的项目还没有完全结束&#xff0c;这几天又有可能涉及到一个新项目。感想随笔记录一下&#xff0c;防止忘记。今天一天整理这个&#xff0c;搞得今天没时间看数学和AI。 在 Unity3D 游戏前端主程序的立项时期&#xff0c;核心目标是明确技术方向、评估可行性、搭建基础…

LCS算法(文本相似度计算)

文章目录 1.dp2.dp&#xff08;单数组优化&#xff09; LCS&#xff0c;Longest Common Subsequenc&#xff0c;最长公共子序列&#xff0c;子序列在原序列中可以不连续&#xff0c;但必须先后顺序保持一致。例如ABCD中&#xff0c;BD是一个子序列&#xff0c;DB不是。 LCS常被…

CentOS 8 停止维护后通过 rpm 包手动安装 docker

根据 Docker官方文档 的指引&#xff0c;进入 Docker rpm 包下载的地址&#xff0c;根据自己系统的架构和具体版本选择对应的路径 这里使用 Index of linux/centos/7/x86_64/stable/ 版本&#xff0c;根据 docker 官方的给出的安装命令选择性的下载对应的 rpm 包 最终使用 yum …

【OCR】总结github上开源 OCR 工具:让文字识别更简单

前言 在数字化的时代&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术成为了我们处理文档、图像文字信息的得力助手。它能够将图像中的文字信息转换为可编辑和可处理的文本数据&#xff0c;极大地提高了信息处理的效率。今天&#xff0c;我要给大家介绍一些优秀的开源…

在 VSCode 远程开发环境下使用 Git 常用命令

在日常开发过程中&#xff0c;无论是单人项目还是团队协作&#xff0c;Git 都是版本管理的利器。尤其是在使用 VSCode 连接远程服务器进行代码开发时&#xff0c;Git 不仅能帮助你管理代码版本&#xff0c;还能让多人协作变得更加高效。本文将介绍一些常用的 Git 命令&#xff…