【Linux进程详解】进程地址空间

news2024/9/21 10:46:09

目录

1.直接写代码看现象

2.引入最基本的理解

3.细节问题-理解它


1.直接写代码看现象

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
int g_val = 100;

int main()
{
    printf("father is running, pid: %d, ppid: %d\n", getpid(), getppid());


    pid_t id = fork();
    if(id == 0)
    {
        //child
        int cnt = 0;
        while(1)
        {
            printf("I am child process, pid: %d, ppid: %d. g_val: %d, &g_val: %p\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
            cnt++;
            if(cnt == 5)
            {
                g_val = 300;
                printf("I am child process, change %d -> %d\n", 100, 300);
            }
        }
    }
    else
    {
        //father
        while(1)
        {
            printf("I am father process, pid: %d, ppid: %d. g_val: %d, &g_val: %p\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
        }
    }
}

并且我们还能观察到,从一开始父子进程便是相同的

由此可推出,我们打印出来的地址绝对不是物理地址,而是虚拟地址,故我们在C/C++中看到的地址是虚拟地址,由操作系统负责转化为物理地址

关于地址,从低地址到高地址存储的依次是:代码段、初始化全局数据区、未初始化全局数据区、堆区、栈区、命令行参数与环境变量。其中,堆区的空间是从小到大增长的,而栈区的空间是从大到小增长的

其中在32位机器中,使用32位(比特位)来表示一个地址,这意味着它可以表示 2^32个不同的地址,也就是4GB;在64位机器中,使用64位(比特位)来表示一个地址,它可以表示 2^64 个不同的地址,也就是16EB

需要注意的是,这里的EB指的是艾字节(Exabyte),1EB等于 1,0241,024 PB(拍字节),而1PB等于 1,0241,024 TB(太字节),1TB等于 1,0241,024 GB(千兆字节),1GB等于 1,0241,024 MB(兆字节),1MB等于 1,0241,024 KB(千字节),1KB等于 1,0241,024 字节。因此,16EB是一个非常巨大的数字,远远超过了当前大多数应用场景的需求。

2.引入最基本的理解

我们在回到刚刚代码示例那里,当子进程修改g_val的值时,为了保证进程之间的独立性(也即是说,子进程的数值修改不应该影响父进程),此时就会发生写时拷贝,会给子进程的g_val开辟独立的物理地址空间,而不是与父进程共享同一块空间,通过观察我们发现,代码依旧共享同一块空间,只是数据区不同了而已

 

3.细节问题-理解它

  • 什么叫做地址空间?

在32位机器下,数据与地址总共32根线,每根数据与地址线可以产生充电和放电两种状态,即产生0或1。因此地址总线排列组合形成地址范围为[0, 2^32 ],这就是地址空间

  • 如何理解地址空间上的区域划分

【示例】小学生划分38线

张三和李四是同桌,桌子共长200cm,他们约定每人100cm。即课桌划分为[0,100], [101,200]这两个区域划分,如果要记录区域的结果,我们就需要先描述再组织

struct desktop{
  int zhangsan_start;
  int zhangsan_end;
  int lisi_start;
  int lisi_end;
};

操作系统为每个进程创建了进程地址空间和mm_struct,用于记录每个进程的各个区域的起始位置和结束位置。在已经被分配给某进程的空间范围内,该进程可以随意使用和访问

  • 为什么要有进程地址空间?

【示例】大富翁的3个私生子

远在几千万千里的大富翁有三个私生子,3个私生子互相不知道对方的存在。这个大富翁对每一个私生子说,我有100亿,等我某一天驾鹤西去,这100亿都是你的。当某个儿子有需求时,他像父亲申请10w,此时大富翁就给他10w。但如果申请100亿,可能无法成功(因为有一部分被大富翁其他私生子占用了),但他并不会觉得这100亿不是他的,而是觉得自己申请的太多了

 

而这里的大富翁等同于操作系统,而这三个私生子等同于系统上的进程。操作系统有4GB的内存空间,进程坚信自己拥有操作系统的全部空间,但通常情况下,进程并不会申请过大的空间。

 

因此:1️⃣将无序变成有序,让进程以统一视角看待物理内存以及自己运行的各个区域,

在操作系统中,虚拟内存是一种内存管理功能,它让每个进程都认为自己拥有连续的、独立的地址空间,即使物理内存可能是不连续的,并且被多个进程共享。这样,每个进程都感觉自己拥有整个内存,而实际上它们是在操作不同的物理内存区域。这种抽象提供了以下几个好处:

因此:1️⃣将无序变成有序,让进程以统一视角看待物理内存以及自己运行的各个区域,

在操作系统中,虚拟内存是一种内存管理功能,它让每个进程都认为自己拥有连续的、独立的地址空间,即使物理内存可能是不连续的,并且被多个进程共享。这样,每个进程都感觉自己拥有整个内存,而实际上它们是在操作不同的物理内存区域。这种抽象提供了以下几个好处:

进程隔离:每个进程都不能访问其他进程的内存,这增强了系统的稳定性和安全性。

内存保护:操作系统可以设置权限,防止进程访问它不应该访问的内存区域。

内存扩展:通过虚拟内存,系统可以使用硬盘空间作为临时的内存使用,即交换空间(swap space),从而扩展可用内存的大小。

【示例2】:压岁钱的管理

小明新年获得了200块压岁钱,母亲担心小明会乱花钱,于是和小明说“你的压岁钱由我来保管,你需要买什么就和我说,我在从这里给你钱”。于是有一天小明要买一款游戏机150元,找妈妈去要,结果妈妈说“游戏机,会害了你的学习,不给买”。再一次小明要去买学习资料,向妈妈申请50块钱,妈妈同意了。因此,新增一个人,作为中间层,可以对非法请求进行拦截

因此:在操作系统中,页表除了包含虚拟地址到物理地址的映射关系,还记录了该区域的读写权限。当用户对其已申请空间做了超出读写权限外的操作,则会被操作系统识别到,并终止该进程。

也就是2️⃣操作系统会拦截非法请求-->对物理内存进行保护

注意:物理地址本身没有读写权限,我们在语言中的const等限制某个地址空间的读写权限,本质是在页表中添加读写权限

如果直接使用物理地址而不是虚拟地址,当我们对也指针进行访问时,由于物理地址没有读写权限控制,导致我们修改了其他进程的数据,破坏了进程的独立性。因此,使用虚拟地址+页表的方式可以保证进程的独立性

在操作细则中,由于内存空间十分宝贵,进程中的代码和数据不一定会被全部加载到内存,因此页表中还有一个字段,表示虚拟地址指向的代码和数据是否在磁盘上。如果虚拟地址映射物理地址时,发现该数据或代码位于磁盘上,则会引发页中断(即当前页表无法映射),此时系统在将对应的代码和数据加载到内存中

★ 惰性加载是一种按需加载资源(如图片、视频、脚本或其他数据)的策略,仅在真正需要时才进行加载。这与预加载(Preloading)相反,预加载是在页面加载时提前加载所有可能需要的资源。

同时,如果因为内存资源紧张,可能会将某个进程挂起,即将它的代码和数据先保存到磁盘中,待内存资源不紧张时再重新加载,但重新加载后的物理地址可能与之前的物理地址不再相同。假设进程没有使用虚拟地址空间+页表映射的方式,则每次将进程代码和数据加载到内存就需要改动PCB到地址空间内容,而不是修改页表的内容。这样将使得进程管理与内存管理耦合度过高。同时,物理内存中几乎所有的数据和代码都是乱序的,由于页表的存在,它可以将物理地址和虚拟地址进行映射,在进程视角,可以将内存分布有序化

因此:3️⃣因为有地址空间和页表的存在,将进程管理模块和内存管理模块进行了解耦合

此时我们也可以知道C/C++申请的地址是虚拟地址。

此时我们要重新定义一下我们对进程的概念进程=内核数据结构(PCB+页表+进程地址空间)+代码和数据

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2122980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常回家看看之house of kiwi

house of kiwi 前言&#xff1a;house_of_kiwi 一般是通过触发__malloc_assert来刷新IO流&#xff0c;最后可以劫持程序流或者通过和setcontext来打配合来进行栈迁移来得到flag。 我们看看触发的源码 #if IS_IN (libc) #ifndef NDEBUG # define __assert_fail(assertion, fi…

MFC之CString类及其成员函数用法详解

CString是 CStringT(属于MFC 和 ATL 之间共享的类) 的类模板的专用化&#xff0c;没有基类。在头文件atlstr.h中可以看到CString的定义&#xff1a; CString对象由可变长度的一队字符组成。CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE&#xff0c;则…

Leetcode 300. 最长递增子序列 记忆化搜索、贪心二分 C++实现

Leetcode 300. 最长递增子序列 问题&#xff1a;给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是…

猫头虎推荐:2024国内好用的PyPIP换源库

猫头虎推荐&#xff1a;2024国内好用的PyPIP换源库&#x1f525;&#x1f680; 在国内使用 Python 时&#xff0c;由于访问官方的 PyPI 速度较慢甚至无法连接&#xff0c;选择一个可靠的国内 PyPI 镜像源至关重要&#x1f4c8;。为了更高效地完成项目开发&#xff0c;今天猫头…

BC172 牛牛的排列数(c 语言)

1.我们先输入n m的数字&#xff0c;因为n!/(n-m)!的阶乘。即4&#xff01;4*3*2*1&#xff0c;2&#xff01;2*1&#xff0c;4&#xff01;/2&#xff01;12.或者4&#xff01;4*3*2&#xff01;。 #include<sdtio.h> int main() {int n 0;int m 0;long long a 1;whi…

Leetcode面试经典150题-55.跳跃游戏

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public boolean canJump(int[] nums) {/**如果就一个位置&#xff0c;你本来就在这&#xff0c;肯定可以跳到*/if(nums.length 1) {return true;}/**这个题的解题思路是遍历数组&#xff0c;如果当前位置不在之…

Linux网络——从《计算机网络》到网络编程

文章目录 从《计算机网络》到网络编程从计算机到计算机网络解决问题网络与计算机系统计算机网络的传输流程IP地址与MAC地址 从《计算机网络》到网络编程 科班的同学大多学过计算机网络&#xff0c;而非科班的同学也多多少少听说过一些 计算机网络体系十分繁杂且精妙&#xff…

毕业论文任务书怎么写?超详细指导带你轻松搞定!

AIPaperGPT&#xff0c;论文写作神器~ https://www.aipapergpt.com/ 毕业论文任务书是毕业论文的“指路明灯”&#xff0c;是论文写作的路线规划。很多同学把毕业论文任务书当作形式化的文件草草了事&#xff0c;其实不然。任务书不仅是你整个论文写作的起点&#xff0c;也是确…

艺术体操与骑行的完美协奏:维乐Angel Rise+坐垫,激情与力量的展现!

在艺术体操的赛场上&#xff0c;每一次旋转、每一次跳跃&#xff0c;都凝聚着运动员的力量与技巧。这不仅是一场速度与激情的碰撞&#xff0c;更是一次力量与技巧的交融。正如在骑行的领域里&#xff0c;VELO Angel Rise坐垫以它独特的一体成型设计和技术&#xff0c;为骑行者们…

【论文分享精炼版】 sNPU: Trusted Execution Environments on Integrated NPUs

今天在COMPASS分享了之前写的一个博客&#xff0c;做了进一步的提炼总结&#xff0c;大家可以看看原文~ 今天分享的论文《sNPU: Trusted Execution Environments on Integrated NPUs》来自2024年ISCA&#xff0c;共同一作为Erhu Feng以及Dahu Feng。并且&#xff0c; 这两位作…

《逆水寒手游》在苹果官网亮眼,国产武术游戏激起海外玩家热情

易采游戏网9月10日消息&#xff1a;《逆水寒手游》自上线以来&#xff0c;以其精致的画面、引人入胜的剧情以及创新的玩法&#xff0c;迅速在国内外游戏市场中占据一席之地。如今&#xff0c;这款备受期待的手游更是亮相全球科技巨头苹果公司iPhone16Pro的官网&#xff0c;为全…

lunix磁盘IO await until问题实战排查-实用命令集合

1、Linux查看磁盘读写次数 iostat -x 1 这个命令可以查询磁盘当前平均读写的次数、读写&#xff0c;以及是否await util严重。 2、查看磁盘TPS和读写数据量大小 iostat -d -k 1 10 这个命令可以查看磁盘的tps和读写数据量大小。 -d&#xff1a;显示某块具体硬盘&#x…

已知两圆的圆心半径,求交点坐标——CAD VBA 解决

如下图&#xff0c; dwg图中若干图形&#xff0c;运行代码后提示选择两个圆&#xff0c;然后判断两个圆位置关系和相交点坐标: 本例难点在于通过几何知识求出交点坐标。 几何背景 假设有两个圆&#xff1a; - 圆1&#xff1a;圆心 ( O_1(x_1, y_1) )&#xff0c;半径 ( r_1 ) …

关于支付宝小程序多规格选项的时候点击不起反应的原因分析及修改方法

解决方案&#xff1a; watch的时候&#xff0c;对于对象的赋值&#xff0c;最好用深拷贝&#xff0c;即如下图&#xff1a; watch:{ row: function (nv, ov) {var that this;that.indata.row JSON.parse(JSON.stringify(nv));//如果是对象&#xff0c;请用深入的for (va…

《使用 LangChain 进行大模型应用开发》学习笔记(二)

前言 本文是 Harrison Chase &#xff08;LangChain 创建者&#xff09;和吴恩达&#xff08;Andrew Ng&#xff09;的视频课程《LangChain for LLM Application Development》&#xff08;使用 LangChain 进行大模型应用开发&#xff09;的学习笔记。由于原课程为全英文视频课…

ReLU再进化ReLUMax:自动驾驶的瞬态容错语义分割

ReLU再进化ReLUMax&#xff1a;自动驾驶的瞬态容错语义分割 Abstract 度学习模型在自动驾驶感知中至关重要&#xff0c;但其可靠性面临着算法限制和硬件故障的挑战。我们通过研究语义分割模型的容错性来应对后者。使用已有的硬件故障模型&#xff0c;我们在准确性和不确定性方…

视频号接口列表

目前已有的接口列表&#xff1a; 账号搜索 视频搜索 直播搜索 获取作者信息和作品列表 视频解密并下载 获取视频详情 获取视频评论 获取视频评论的子评论 作品喜欢 作品点赞 作品评论 对作品评论进行评论 关注作者 加入直播间 获取直播间弹幕消息 发送弹幕消息 获取直播间商品…

力扣474-一和零(Java详细题解)

题目链接&#xff1a;474. 一和零 - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完01背包&#xff0c;所以现在的题解都是以01背包问题为基础再来写的。 如果大家不懂01背包的话&#…

运维问题0002:SAP多模块问题-SAP系统程序在执行时,跳出“加急快件”窗口,提示:快件文档“更新已终止”从作者***收到

1、问题描述 近期收到2起业务报障&#xff0c;均反馈在SAP执行程序时&#xff0c;弹出“加急快件”窗口&#xff0c;导致操作的业务实际没有更新完成。 1&#xff09;业务场景一&#xff1a;设备管理部门在操作事务代码&#xff1a;AS02进行资产信息变更时&#xff0c;保存正常…

面试官:为什么 Redis 6.0 之后引入多线程?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 回答 Redis 的性能瓶颈从来都不是 CPU&#xff0c;是网络I/O 和内存。 内存好解决&#xff0c;加机器内存和优化数据结构。 网路 I/O 的优化才是大头&#xff0c;因为读写网络的 read…