首页 > 系统相关 >进程地址空间

进程地址空间

时间:2024-11-16 21:18:01浏览次数:3  
标签:虚拟地址 gval 空间 地址 页表 进程 内存

1.进程的地址空间

在讲程序地址空间,我们先看一段代码和现象:

#include <stdio.h>
#include <unistd.h>

int gval = 100;

int main()
{
    printf("我是一个进程,pid: %d,ppid: %d\n", getpid(), getppid());
    pid_t id = fork();
    if (id == 0)
    {
        // child
        while (1)
        {
            printf("我是子进程,pid: %d,ppid: %d,gval: %d,&gval: %p\n", getpid(), getppid(),gval,&gval);
            gval++;
            sleep(1);
        }

    }
    else
    {
        //parent
        while(1)
        {
            printf("我是父进程,pid: %d,ppid: %d,gval: %d,&gval: %p\n", getpid(), getppid(),gval,&gval);
            sleep(1);
        
        }
    }
    return 0;
}

一个全局变量,子进程对其进行++,父进程不进行操作,分别对其取地址,最后发现都指向相同的地址空间,但是怎么可能对相同的地址空间进行读取,父进程读的数不变,子进程一直改变,这种情况是不可能产生的。

  • 变量内容不⼀样,所以⽗⼦进程输出的变量绝对不是同⼀个变量
  • 但地址值是⼀样的,说明,该地址绝对不是物理地址!

1.虚拟地址/线性地址

由于父子进程对相同地址读取,值不一样,我们可以进行推断,这个地址肯定不是物理地址,

如果是物理地址,就不可能不同的进程,一个查出来值不变,一个查出来值在进行改变,因为两地址是一模一样的,所有此处一定不是物理地址。

由此,就可以引出了一个概念:虚拟地址/线性地址,此处打印的地址为虚拟地址。

1.是什么?

在Linux中,会存在一个虚拟地址,本质就是一个内核数据结构对象(类似PCB),

在Linux中以mm_struct命名,就是该虚拟地址空间的内核数据对象,

在虚拟地址中有各个区域,那么这些区域是怎么进行划分维护的呢?

本质就是空间区域的划分!!也就是说,只需要告诉开头与结尾就可以确定一个空间范围。

在mm_struct中对其进行了维护:

start表示开头,end表示结尾,这样就可以划分好区域。

怎么理解地址空间上的地址?

  • 地址本来就是一个数子,可以被保存在unsigned long (4字节)中
  • 空间范围内的地址,可以随便使用,暂时不需要记录下来

虚拟地址被维护在进程PCB中,当我们创建一个进程时,不仅要创建PCB,还要创建他的虚拟地址空间。 

在OS中还存在一张页表,他是其映射作用,虚拟地址通过页表进行映射可以访问到物理地址空间。

 再来看上面代码,由于子进程拷贝父进程代码数据,同时也会拷贝task_struct,mm_struct,页表。

由于拷贝,所以子进程与父进程虚拟地址相同,所以此时子进程与父进程指向同一个区域gval,

当子进程要对这个区域的gval进行修改,又不能影响父进程的值,此时就有了写时拷贝,当OS发现子进程要修改的区域与父进程冲突后,才会会进行写时拷贝,在物理内存上新开辟一个空间,如后把gval值拷贝过来,就可以对其进行修改,同时又不影响父进程。那么此时只需要修改子进程通过虚拟地址映射的物理地址即可,这样,在上层观察到父子进程打印的虚拟地址相同,但底层取指向不同的地址空间。

写实拷贝的意义?

因为每次创建子进程,都会拷贝父进程代码数据,消耗比较大,所以对于一些只读的代码就可以不进行拷贝,父子进行代码共享,当子进程或父进程想要对其进行修改,这时OS就会自主进行写时拷贝,达到有效节省空间的目的。

所以 ,进程=内核数据结构(task_struct/mm_struct/页表)+代码和数据

关于页表:

可以理解成跟哈希表一样的结构,可以通过映射来找数据。

页表有很多标记位,有个涉及rwx权限方面,一个是表示所指向的内存空间是否存在。

通过权限进行限定行为,

这段代码为什么不能对其进行修改,是因为这个代码区域被设置为了只读区域,当进行写入时,OS发现违法操作,就会对其直接杀掉。

当进程被创建,是先创建页表,还是先把可执行程序从磁盘加载到物理内存中?

先创建页表,后进行加载程序。在程序加载到内存之前,需要先建立好页表,以便在程序运行时能够准确地将程序中的虚拟地址转换为物理地址。如果先加载程序而没有页表,处理器在执行程序时就无法确定虚拟地址对应的物理地址,程序也就无法正确运行。

另一个标记位isexists,表明当前虚拟地址,物理地址的映射所对应的空间是否在内存中存在,为什么会这样说呢?因为假设一个很庞大的程序,他不可能全不加载进内存,如果全部加载进内存,就会发生浪费,因为半天运行不到后面代码,此时后面代码所站空间就会发生浪费,所以当一个程序加载进内存不是全部一次性加载。

所以这时就需要判断所对应的内存是否存在,如果不存在,要么是还没加载进来,要么是被切换出去了,但是如果要进行访问了,会把数据重新从外设做换入动作。

这个标记位支撑着:1.分配加载,2.挂起等操作。

关于地址空间:

指令readelf ,可以查看可执行程序的信息,

虚拟地址空间也是结构体,也需要初始化,那么怎么初始化呢?

可执行程序进行编译的时候,就已经拿到各个区域大小的信息,mm_struct初始化,从可执行程序来的。可执行程序包括:1.区域分段,2.包含属性,所以操作系统(进程管理),编译原理,可执行程序相互之间有关系。

2.为什么?

为什么存在虚拟地址空间和页表?

1.保护内存

比如为什么叫做野指针,为什么野指针程序就崩溃了?

根本原因,就是野指针,在C/C++中,用的地址是虚拟地址,在转换为物理地址的时候,要么权限不允许,要么不存在对应的映射,所以OS就会杀死这个进程。起到保护作用!!

2.有虚拟地址空间和页表的存在,使进程管理与内存管理在系统层面上进行了解耦合,如果没有其存在,耦合度太高,不好分别进行管理

3.让进程以统一视角进行看待物理内存,可执行程序代码数据加载到物理内存的任意位置处,因为有页表进行映射,就可以让无序变成有序,统一看待物理内存以及各个区域。

3.怎么办

地址空间本质是一个struct mm_struct,所有内容都是OS自主进行完成的,所以只要把进程管理好,地址空间就管理好了。

全局变量,字符常量------具有全局性,在程序运行期间一直存在有效----->为什么?--->在地址空间中,随着进程,一直存在,全局变量的虚拟地址,一直可以被看见!!!

标签:虚拟地址,gval,空间,地址,页表,进程,内存
From: https://blog.csdn.net/2302_80652761/article/details/143820934

相关文章

  • 第六章 网络互连与互联网(六):域名和地址
    六、域名和地址Internet地址分为3级,可表示为“网络地址·主机地址·端口地址”的形式。其中,网络和主机地址即 IP地址:端口地址就是 TCP 或UDP地址,用于表示上层进程的服务访问点。TCP/IP网络中的大多数公共应用进程都有专用的端口号。下表列出了主要的专用端口......
  • mac_OS虚拟机VMware Fusion定制虚拟网卡IP地址
     cd/Library/Preferences/VMware\FusionvimnetworkingVERSION=1,0answerVNET_1_DHCPyesanswerVNET_1_DHCP_CFG_HASH4C38E57B8B33183E68351DF648C7C5182A8EDC90answerVNET_1_HOSTONLY_NETMASK255.255.255.0answerVNET_1_HOSTONLY_SUBNET172.16.224.0answe......
  • 进程、线程、协程
    进程、线程、协程文章目录进程、线程、协程一、进程的出现二、线程的出现三、协程协程与函数的区别协程如何实现?**协程与线程的区别**多个执行流但只有一个线程为什么要使用协程?一、进程的出现CPU是不知道进程、线程的概念的,CPU只知道做两件事情。从内存中读取指......
  • 配置proxyRes 可在响应头中看到请求的真实地址
    在Vite配置中,proxy选项用于设置开发服务器的代理规则。通过这些代理规则,你可以将前端开发服务器的请求转发到后端API服务器,从而解决开发环境中的跨域问题。你提到的配置片段详细地设置了代理规则,下面是对这段代码的详细解释:代码解析proxy:{[viteEnv.VITE_BASE_API]:{......
  • 【Linux进程篇1】认识冯·诺依曼体系结构(引出进程详解)
    ---------------------------------------------------------------------------------------------------------------------------------每日鸡汤:用这生命中的每一秒,给自己一个不后悔的未来。-------------------------------------------------------------------------......
  • Linux:进程状态
    文章目录前言一、初识fork1.1fork函数的介绍1.2fork出的子进程存在形式1.3写时拷贝二、进程的状态2.1Linux内核源代码2.2理解内核链表(重要)2.3运行状态2.4阻塞状态2.5挂起状态三、Z(zombie)状态,僵尸进程四、孤儿进程总结前言本文将介绍如何利用系统调用......
  • 【Linux】:进程信号(信号保存 & 信号处理)
    ✨                         落日一点如红豆,已把相思写满天    ......
  • 进程的知识点
    进程的基本概念进程是操作系统中的一个执行单位,代表正在运行的程序实例。每个进程都有自己独立的内存空间和系统资源,独立于其他进程运行。进程的生命周期包括创建、就绪、运行、等待和终止等状态。进程的创建与管理在操作系统中,进程的创建和管理通常通过系统调用实现,如fork(......
  • 【Linux探索学习】第十三弹——进程状态:深入理解操作系统进程状态与Linux操作系统中的
    Linux笔记:https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482前言:在上篇我们已经讲解了进程的基本内容,也了解了进程在操作系统的重要作用,今天我们正式开始进程的另一个知识点的讲解:进程状态,即一个进程不可能一直处在运行或终止状态中,它......
  • 【深入浅出】之Linux多进程实现shell外壳程序(简易版)
    ......