程序地址空间

ops/2024/10/9 12:51:04/

文章目录

  • 程序地址空间
  • 进程地址空间
    • 关于页表
  • 早期内存的分配方式

程序地址空间

计算机得物理内存大小是固定的,就是计算机主板内存槽上的实际物理空间,CPU可以直接继续寻址,物理内存的容量是固定的,但是寻址的卡空间取决于CPU地址线的数量。32位系统上,线性地址空间可达4G,那么这4G的内存是如何分配的呢?一般情况下,是以3:1来分配的,用户进程配有3G的空间,而内核独自配有1G的内存。
C语言学习期间,大家都学习了这样得空间分布图:
空间分布图

写段代码来测试一下吧

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int val = 10;
int main()
{pid_t id = fork();if(id<0){perror("fork");return 0;}if(id == 0){//childprintf("child[%d] val = %d &val = %p\n",getpid(),val,&val);}else{//parentprintf("parent[%d] val = %d &val = %p\n",getpid(),val,&val);}sleep(1);return 0;
}
//打印结果:
/*
parent[1297] val = 10 &val = 0x60104c
child[1298] val = 10 &val = 0x60104c
*/

我们发现,输出出来的变量和地址是一模一样的,难道是因为子进程是按照父进程位模板,父子并没有对变量进行任何修改?

那么我们换一个代码版本来看看。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int val = 10;
int main()
{pid_t id = fork();if(id<0){perror("fork");return 0;}if(id == 0){//childval = 100;printf("child[%d] val = %d &val = %p\n",getpid(),val,&val);}else{//parentsleep(3);//让子进程先运行完printf("parent[%d] val = %d &val = %p\n",getpid(),val,&val);}sleep(1);return 0;
}
//打印结果
/*
child[1948] val = 100 &val = 0x60104c
parent[1947] val = 10 &val = 0x60104c
*/

什么!一样的地址居然存放着不同的值!这是不可能的。
那么真相就出来了。

  • 变量内容不一样,所以父子进程输出的变量绝对不是一个同一个变量。
  • 但是显示的地址相同,就说明了该地址绝对不是物理地址。
  • 在Linux地址下,这种地址叫做虚拟地址。
  • 我们在使用C/C++语言所看到的地址,全部都是虚拟地址,物理地址用户是看不到的,由OS统一管理。
    操作系统OS赋值将虚拟地址转化位物理地址

进程地址空间

先前所说的程序的地址空间是不正确的,准确的应该说成进程地址空间,那该如何理解呢?
进程地址空间

同一个变量,地址相同,其实是虚拟地址相同,内容不同是因为映射到了不同的物理地址。

关于页表

页表的概念:

  • 页表是一个特殊的数据结构,放在内存空间的页表区。
  • 每一个进程都有一个页表,PCB表中有指针指向页表。
  • 页表用来存放逻辑地址于物理地址的对应关系,是否映射,是否缓存。
  • 页表的每一个表项分为两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存的地址
  • 当进程访问某个虚拟进程地址时,会去查页表,如果发现对应的数据没有在物理内存上,则会发现缺页异常。
  • 缺页异常异常处理过程:将进程需要覆盖的数据从磁盘中拷贝到物理内存时,如果物理内存满了,没有空地方了,那就找一个页覆盖,当如果被覆盖的页曾经被修改过,就需要将此页写回磁盘。
    页表的状态
  • 如果页表的有效位置为1,那么就说明虚拟地址存储的内存存在物理页中了。
  • 如果页表的有效位置为0,那么就说明虚拟地址存储的内存没有存储在物理页中,发生了缺页异常,需要处理这个异常。
    页表的工作原理
  • 当CPU想访问父进程的val时,会先根据虚拟地址找到虚拟页,根据页表,找出页表val对应的位置,查看该页表是否有效,有效则为1,DRMA换命中,根据物理页中的内容返回。
  • 若无效(0),则参数缺页异常,调用内核缺页异常处理程序,内核会选择一个无理由作为牺牲页,将该页的内容刷新到磁盘空间,然后将val映射到物理页上面,然后页表中该表有效位置1,第二位存对应的物理页的地址内容。
  • 缺页处理完成后,返回中断前的指令,重新指向,此时缓存命中,执行1.
  • 将找到的内容映射到告诉缓存中,CPU从告诉缓存中获取该值,结束。

早期内存的分配方式

在早期的时候,计算机还没有虚拟机制,程序指令所访问的内存地址就是物理地址,所以就要将所有程序都加载到内存中,但是我们实际的物理内存是有限的,那么就会出现一些问题:

  • 当多个程序重新运行时,必须保证这些内存用到的内存总量小于计算机实际的物理内存的大小。
  • 内存使用效率低,内存空间不足,就需要将其他程序暂时拷贝到硬盘中,然后重新将新的程序装入内存,但是由于大量的数据转入与转出,内存的使用效率会非常低。
  • 进程地址空间不隔离,由于空间时直接访问物理内存的,所以每一个进程都可以修改其他进程的内存数据,设置修改内核地址空间的数据,那么可能会导致一些恶意程序可以随意修改别的进程,就会造成一些破坏。
  • 程序运行地址的不确定,因为内存地址是随机分配的,所以程序运行的地址也是不正确的。
    为此才会引入虚拟地址。用户进程间的地址互补可见,互不影响。

http://www.ppmy.cn/ops/120508.html

相关文章

高精度(3)——高精度乘法

题目描述 给定两个非负整数&#xff08;不含前导 0&#xff09;A 和 B&#xff0c;请你计算 A B的值。 输入格式 共两行&#xff0c;第一行包含整数 A &#xff0c;第二行包含整数 B。 输出格式 共一行&#xff0c;包含A B的值。 数据范围 1≤A的长度≤100000, 0 ≤ B…

iOS--App启动过程及优化

前言 App启动是用户对于一个app的第一印象&#xff0c;因此如何使用户在最短的时间打开进入app显得格外重要。启动优化因此成为了App调优至关重要的一项。 只有具体了解了App的启动过程&#xff0c;我们才能对其进行优化。 App启动过程 App启动分为冷启动和热启动 热启动&…

jenkins微服务

如果vim进去某个文件里&#xff0c;可以按键盘的向下键查阅其它部分 记得每天备份虚拟机的项目 一.在linux安装jenkins 1.上传文件 我们采用安装包的方式安装。 先用SShclient在/usr/local/下创建jenkins文件夹&#xff0c;然后向其中导入两个包 2.安装jenkins 再在控制…

超轻巧modbus调试助手使用说明

一、使用说明 1.1 数据格式 和其他的modbus采集工具一样&#xff0c;本组件也支持各种数据格式&#xff0c;其实就是高字节低字节的顺序。一般是2字节表示一个数据&#xff0c;后面又有4字节表示一个数据&#xff0c;目前好像还有8字节表示一个数据的设备。不同厂家的设备对应…

智慧防灾,科技先行:EasyCVR平台助力地质灾害视频监测系统建设

随着科技的飞速发展&#xff0c;视频监控技术已成为地质灾害监测与预警的重要手段之一。在众多视频监控平台中&#xff0c;EasyCVR视频汇聚平台凭借其强大的视频整合、实时传输、视频处理及分发等能力&#xff0c;在地质灾害场景中展现出显著的应用优势。 一、实时监测与远程监…

docker(1) --- win11环境配置

1. 下载Docker Desktop 点击这里可下载最新版的程序&#xff0c;我这边在浏览器中无法直接下载&#xff0c;最后使用迅雷完成了下载&#xff0c;当前版本为4.33.1&#xff0c;文件大小492.4MB。这里也有个阿里云的下载链接&#xff0c;但是不是最新的版本docker-for-windows&a…

华为云LTS日志上报至观测云最佳实践

华为云LTS简介 华为云云日志服务&#xff08;Log Tank Service&#xff0c;简称 LTS&#xff09;&#xff0c;用于收集来自主机和云服务的日志数据&#xff0c;通过海量日志数据的分析与处理&#xff0c;可以将云服务和应用程序的可用性和性能最大化&#xff0c;为您提供实时、…

技术速递|加入 .NET 智能组件生态系统

作者&#xff1a;Daniel Roth - 首席产品经理 排版&#xff1a;Alan Wang .NET 智能组件是一组示例嵌入式 UI 组件&#xff0c;使得在应用中轻松添加 AI 启用的功能变得更加简单&#xff0c;例如从剪贴板数据自动填写表单、智能文本补全以及语义搜索等场景。.NET 智能组件演示了…