首页 > 系统相关 >【Linux】对进程地址空间的理解

【Linux】对进程地址空间的理解

时间:2024-03-24 22:31:45浏览次数:25  
标签:Linux 空间 地址 内存 页表 进程 物理

一、关于进程地址空间的简单理解 

        进程地址空间其实是分了很多个区域的,区域划分的本质就是区域内的各个地址都是可以使用的。如同下面这个图所示:

        无论是环境变量的地址还是环境变量表的地址,所存放的地址都在栈的上部。这里的已初始化数据和未初始化数据是指的全局变量,包括静态变量(静态变量默认被初始化为0)。 进程地址空间不是真实的物理内存,叫做虚拟内存。每一个进程都有自己独立的PCB,也有自己独立的地址空间。在32位机器下,进程地址空间的大小为[0,4GB]。其中,PCB会记录一个进程的起始地址或基地址,这其实就是进程地址空间的首地址。进程地址空间和真实的物理内存之间有一个叫做页表的结构,页表存放的就是虚拟内存到物理内存之间的映射关系,所以通过虚拟内存经过一定步骤就可以访问到真实物理内存中的内容。

        上面图的地址空间和页表都是操作系统帮我们维护的。当父进程创建子进程的时候,操作系统会把上面的这些结构以及结构中的内容给子进程爷拷贝一份。所以在子进程刚创建出来时跟父进程是访问同一块物理内存的。当子进程要对数据做修改时会发生写实拷贝,给子进程要修改的数据重新开辟一块物理空间,再将重新开辟的这块物理空间的地址填充入子进程的页表中,但此时页表中对应的虚拟地址并没有发生变化,所以可以看到父子进程访问同一个虚拟地址却打印出不同的内容。

#include <stdio.h>
#include <unistd.h>
int main()
{
    int x = 10;
    pid_t id = fork();
    if(id == 0)
    {
        x=20;
        while(1)
        {
            printf("子进程pid:%d, ppid:%d, x=%d, &x=%p\n", getpid(), getppid(),x,&x );
            sleep(1);
        }
    }
    else
    {
        while(1)
        {
            printf("父进程pid:%d, ppid:%d, x=%d, &x=%p\n", getpid(), getppid(),x,&x );
            sleep(1);
        }
    }
    return 0;
}

示意图: 

         操作系统中可能同时存在多个进程,也就意味着操作系统要对多个进程所对应的进程地址空间通过先描述,再组织的原理做管理。所以,进程地址空间就是数据结构,具体到进程中,就是特定数据结构的对象!

二、为什么要有进程地址空间和页表

1、将物理内存从无序变成有序,让进程以统一的视角看待内存。物理内存可以在任意一个空闲的合法的位置进行申请,一个进程申请的物理内存可以是无序的,但一旦映射到页表中就跟有序的虚拟地址产生了一一对应的关系,将物理内存从无序变成有序。

2、将内存管理和进程管理进行解耦合。内存管理和进程管理可以做到互不干扰。

3、进程地址空间和页表是保护内存安全的重要手段。如果我们的进程非法访问某一个地址(比如说数组越界),我们的进程可能直接就崩了。

三、利用进程地址空间解释一些现象

        操作系统一定要为效率和资源使用率负责。malloc/new申请的内存操作系统并不知道用户什么时候会用,既然不知道什么时候会被使用,那么如果直接申请物理内存系统就无法保证资源使用率。所以,malloc/new申请内存不是在物理内存上直接申请的,而是直接得到的虚拟地址。当操作系统发现用户要向他申请的内存中进行写入合法内容时并且该内存没有在页表中建立对应的映射关系,操作系统就会先拦截住你的这个写入动作,在物理内存中开辟一块空间,并在该进程的页表中建立映射关系,然后操作系统再放开进程让进程进行写入操作,这个就叫做缺页中断。这样就可以充分保证内存的使用率,保证内存不会空转。同时也提升了new/malloc的速度。

标签:Linux,空间,地址,内存,页表,进程,物理
From: https://blog.csdn.net/m0_74265792/article/details/136984081

相关文章

  • linux时间设置
    1.检查当前时区date---显示当前系统时间和日期,格式包括星期几、月份、日期、时间和时区。ortimedatectl---更多的时间和日期管理功能,包括显示当前时间和日期、时区信息、系统启动时间等。2.设置时区为上海/北京时间:sudotimedatectlset-timezoneAsia/Shanghai或者......
  • Linux(五) 进程控制
    一、进程创建1.fork进程=内核数据结构+进程代码和数据 fork之后,进程进入内核态,执行fork的代码,创建子进程,那么OS内核是怎么创建子进程的呢?首先,需要给子进程分配对应的内核数据结构(为了保证进程间的独立型,必须每个进程独有一份)第二,将父进程部分内核数据结构的内容拷......
  • JDK 8、11、13 收费吗?OpenJDK 下载地址
    转载: https://weiku.co/article/348/JDK17免费了JDK17 还是如期发布了,2021年09月14日。巧了,和苹果发布会是一天,不知道是不是互相在蹭热度~JDK17 除了新增了不少新特性,Oracle 官方竟然宣布 JDK17可以免费商用了!OracleJDK17和未来的JDK版本是在免费使用许可下提......
  • Linux 添加开机自启动
    rc.local方式一、&在Linux命令后加上 & 可以在后台运行 二、nohup对SIGHUP信号免疫,对SIGINT信号不免疫,可用shopt|grephup查看。当关闭终端时,shell默认会发送SIGHUP信号给与该终端关联的进程,从而导致其进程跟随终端退出。nohup捕获了SIGHUP,并做了忽略处......
  • Linux 中的以太网管理,以及udhcpc介绍和使用步骤
    在Linux中,udhcpc是一个用于动态获取IP地址的工具,通常用于DHCP(DynamicHostConfigurationProtocol)网络配置。它是BusyBox工具集中的一部分,用于从DHCP服务器获取IP地址、网关、DNS服务器等网络配置信息。以下是udhcpc的基本介绍和使用流程:1.安装udhcpc:udhcpc通常是与BusyBo......
  • 在linux中无需修改内核驱动就能操作GPIO口的示例
    一、首先编写一个脚本文件init.sh#!/bin/bashecho2>/sys/class/gpio/exportsleep1echo3>/sys/class/gpio/exportsleep1echoout>/sys/class/gpio/gpio3/directionecho1>/sys/class/gpio/gpio3/value这段代码是在Linux系统中使用shell脚本语言编写的。让......
  • Linux学习记录13——shell脚本
    一.学习的内容    shell终端解释器提供了诸如循环、分支等高级编程语言才有的控制结构。shell脚本命令的工作方式有下面两种:    交互式:用户每输入一条命令就立即执行        批处理(Batch):由用户事先编写好一个完整的Shell脚本,Shell会一次性执行脚本......
  • linux 下安装mysql redis
    查看是否安装mysql:rpm-qa|grepmysql获取mysql版本:wget-i-chttp://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm安装:rpm-ivhmysql-community-release-el7-5.noarch.rpmyuminstallmysql-community-serversystemctlstartmysqldsystemctlrest......
  • 【Linux应用开发】gcc编译过程
            gcc是一个c编译器,​可以将源代码转换为可执行程序。编译过程包括了预处理、编译、汇编和链接这四个阶段。预处理(Preprocessing):在预处理阶段,源代码会经过预处理器的处理,包括展开宏定义、包含头文件、条件编译等操作。预处理器会生成一个经过预处理的中间文件......
  • Linux收到一个网络包是怎么处理的?
    目录摘要​编辑1从网卡开始2硬中断,有点短2.1GameOver3接力——软中断3.1NET_RX_SOFTIRQ软中断的开始3.2数据包到了协议栈3.3网络层处理3.4传输层处理4应用层的处理5总结摘要    一个网络包的接收始于网卡,经层层协议栈的解析,终于应用层。......