1. 程序地址空间回顾

我们在学习语言层面时,会了解到这样的空间布局图,我们先对他进行分区了解:

如果以静态static修饰的变量就会当成已初始化全局变量来看待,存放在已初始化数据区和未初始化数据区之前。

如果不用static修饰test的话,test只是 

 


2.一个例子引入虚拟地址

输出出来的变量值和地址是⼀模⼀样的,很好理解呀,因为⼦进程按照⽗进程为模版

变量值不一样可以理解,进程之前是具有独立性的,即便是父子进程。

但是⽗⼦进程输出地址是⼀致的,但是变量内容不⼀样的 why ???

但是为什么输出地址一模一样却有两个不同的值呢?

⽗⼦进程,输出地址是⼀致的,但是变量内容不⼀样!能得出如下结论:

变量内容不⼀样,所以⽗⼦进程输出的变量绝对不是同⼀个变量
但地址值是⼀样的,说明,该地址绝对 不是物理地址!
在Linux地址下,这种地址叫做 虚拟地址
我们在⽤C/C++语⾔所看到的地址, 全部都是虚拟地址 !物理地址, 用户⼀概看不到,由OS统⼀
管理
OS必须负责将 虚拟地址 转化成 物理地址

3.进程地址空间

所以之前说‘程序的地址空间’是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?看
图:
分⻚&虚拟地址空间

 

注:上⾯的图就⾜矣说明问题,同⼀个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!

虚拟地址空间,本质一定是一个内核数据结构!

空间区域划分:本质其实只要有线性空间的一段开始地址和结束地址表明一段范围即可。

区域划分:表明开始地址和结束地址,区域内部的内容都属于我

4. 虚拟内存管理
 

描述linux下进程的地址空间的所有的信息的结构体是 mm_struct (内存描述符)。每个进程只有⼀个mm_struct结构,(操作系统给画的饼)在每个进程的task_struct结构中,有⼀个指针指向该进程的mm_struct结构体指针 。

struct task_struct
{/*...*/struct mm_struct *mm;//对于普通的⽤⼾进程来说该字段指向他的虚拟地址空间的⽤⼾空间部分,对于内核线程来说这部分为NULL。struct mm_struct *active_mm; // 该字段是内核线程使⽤的。当该进程是内核线程时,它的mm字段为NULL,表⽰没有内存地址空间,可也并          不是真正的没有,这是因为所有进程关于内核的映射都是⼀样的,内核线程可以使⽤任意进程的地址空间。/*...*/
}    

可以说,mm_struct结构是对整个⽤⼾空间的描述。每⼀个进程都会有⾃⼰独⽴的mm_struct,(把每一个进程映射到不同的物理内存处)这样每⼀个进程都会有⾃⼰独⽴的地址空间才能互不⼲扰。先来看看由task_struct到mm_struct,进程的地址空间的分布情况:

定位mm_struct⽂件所在位置和task_struct所在路径是⼀样的,不过他们所在⽂件是不⼀样的, mm_struct所在的⽂件是mm_types.h。
 

struct mm_struct
{struct vm_area_struct *mmap; /* 指向虚拟区间(VMA)链表 */struct rb_root mm_rb; /* red_black树 */unsigned long task_size; /*具有该结构体的进程的虚拟地址空间的⼤⼩*///...// 代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。unsigned long start_code, end_code, start_data, end_data;unsigned long start_brk, brk, start_stack;unsigned long arg_start, arg_end, env_start, env_end;//...}

那既然每⼀个进程都会有⾃⼰独⽴的mm_struct,操作系统肯定是要将这么多进程的mm_struct组织起来的!虚拟空间的组织⽅式有两种:


1. 当虚拟区较少时采取单链表,由mmap指针指向这个链表;

2. 当虚拟区间多时采取红⿊树进⾏管理,由mm_rb指向这棵树。

linux内核使⽤ vm_area_struct 结构来表⽰⼀个独⽴的虚拟内存区域(VMA),由于每个不同质的虚拟内存区域功能和内部机制都不同,因此⼀个进程使⽤多个vm_area_struct结构来分别表⽰不同类型的虚拟内存区域。上⾯提到的两种组织⽅式使⽤的就是vm_area_struct结构来连接各个VMA,⽅便进程快速访问。

struct vm_area_struct {unsigned long vm_start; //虚存区起始
unsigned long vm_end; //虚存区结束
struct vm_area_struct *vm_next, *vm_prev; //前后指针
struct rb_node vm_rb; //红⿊树中的位置
unsigned long rb_subtree_gap;
struct mm_struct *vm_mm; //所属的 mm_struct
pgprot_t vm_page_prot;
unsigned long vm_flags; //标志位
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
struct list_head anon_vma_chain;
struct anon_vma *anon_vma;
const struct vm_operations_struct *vm_ops; //vma对应的实际操作
unsigned long vm_pgoff; //⽂件映射偏移量
struct file * vm_file; //映射的⽂件
void * vm_private_data; //私有数据
atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

所以我们可以对上图在进⾏更细致的描述,如下图所⽰:

 

5. 为什么要有虚拟地址空间

这个问题其实可以转化为:如果程序直接可以操作物理内存会造成什么问题?

在早期的计算机中,要运⾏⼀个程序,会把这些程序全都装⼊内存,程序都是直接运⾏在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址。当计算机同时运⾏多个程序时,必须保证这些程序⽤到的内存总量要⼩于计算机实际物理内存的⼤⼩。

那当程序同时运⾏多个程序时,操作系统是如何为这些程序分配内存的呢?例如某台计算机总的内存⼤⼩是128M,现在同时运⾏两个程序A和B,A需占⽤内存10M,B需占⽤内存110。计算机在给程序分配内存时会采取这样的⽅法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分出110M分配给程序B。

这种分配⽅法可以保证程序A和程序B都能运⾏,但是这种简单的内存分配策略问题很多。

  •  安全⻛险

每个进程都可以访问任意的内存空间,这也就意味着任意⼀个进程都能够去读写系统相关内存区域,如果是⼀个⽊⻢病毒,那么他就能随意的修改内存空间,让设备直接瘫痪。

  • 地址不确定

众所周知,编译完成后的程序是存放在硬盘上的,当运⾏的时候,需要将程序搬到内存当中去运⾏,如果直接使⽤物理地址的话,我们⽆法确定内存现在使⽤到哪⾥了,也就是说拷⻉的实际内存地址每⼀次运⾏都是不确定的,⽐如:第⼀次执⾏a.out时候,内存当中⼀个进程都没有运⾏,所以搬移到内存地址是0x00000000,但是第⼆次的时候,内存已经有10个进程在运⾏了,那执⾏a.out的时候,内存地址就不⼀定了

  •  效率低下

 如果直接使⽤物理内存的话,⼀个进程就是作为⼀个整体(内存块)操作的,如果出现物理内存不够⽤的时候,我们⼀般的办法是将不常⽤的进程拷⻉到磁盘的交换分区中,好腾出内存,但是如果是物理地址的话,就需要将整个进程⼀起拷⾛,这样,在内存和磁盘之间拷⻉时间太⻓,效率较低。

存在这么多问题,有了虚拟地址空间和分⻚机制就能解决了吗?当然!

  • 地址空间和⻚表是OS创建并维护的!是不是也就意味着,凡是想使⽤地址空间和⻚表进⾏映射,也⼀定要在OS的监管之下来进⾏访问!!也顺便保护了物理内存中的所有的合法数据 ,包括各个进程以及内核的相关有效数据!
  • 因为有地址空间的存在和⻚表的映射的存在,我们的物理内存中可以对未来的数据进⾏任意位置的加载!物理内存的分配 和 进程的管理就可以做到没有关系,进程管理模块和内存管理模块就完成了解耦合

因为有地址空间的存在,所以我们在C、C++语⾔上new, malloc空间的时候,其实是在地址空间上申请的,物理内存可以甚⾄⼀个字节都不给你。⽽当你真正进⾏对物理地址空间访问的时候,才执⾏内存的相关管理算法,帮你申请内存,构建⻚表映射关系(延迟分配),这是由操作系统⾃动完成,⽤⼾包括进程完全0感知!!

  • 因为⻚表的映射的存在,程序在物理内存中理论上就可以任意位置加载。它可以将地址空间上的虚拟地址和物理地址进⾏映射,在进程视⻆所有的内存分布都可以是有序的。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言学习day17-----位运算

目录 1.位运算 1.1基础知识 1.1.1定义 1.1.2用途 1.1.3软件控制硬件 1.2运算符 1.2.1与 & 1.2.2或 | 1.2.3非 ~ 1.2.4异或 ^ 1.2.5左移 << 1.2.6右移 >> 1.2.7代码实现 1.2.8置0 1.2.9置1 1.2.10不借助第三方变量&#xff0c;实现两个数的交换…

【linux】简单的shell脚本练习

简单易学 解释性语言&#xff0c;不需要编译即可执行 对于一个合格的系统管理员来说&#xff0c;学习和掌握Shell编程是非常重要的&#xff0c;通过shell程序&#xff0c;可以在很大程度上简化日常的维护工作&#xff0c;使得管理员从简单的重复劳动中解脱出来 用户输入任意两…

机构运动分析系统开发(Python实现)

机构运动分析系统开发(Python实现) 一、引言 机构运动分析是机械工程的核心内容,涉及位置、速度和加速度分析。本系统基于Python开发,实现了平面连杆机构的完整运动学分析,包含数学建模、数值计算和可视化功能。 二、系统架构设计 #mermaid-svg-bT8TPKQ98UU9ERet {font…

工程师生活:清除电热水壶(锅)水垢方法

清除电热水壶&#xff08;锅&#xff09;水垢方法 水垢是水加热时自然形成的钙质沉淀物&#xff0c;常粘附在水壶内壁及发热盘上。它不仅影响水的品质&#xff0c;还会缩短水壶的使用寿命&#xff0c;因此需要定期清除。建议根据各地水质不同&#xff0c;每年除垢 2 至 4 次。…

[分布式并行策略] 数据并行 DP/DDP/FSDP/ZeRO

上篇文章【[论文品鉴] DeepSeek V3 最新论文 之 DeepEP】 介绍了分布式并行策略中的EP&#xff0c;简单的提到了其他几种并行策略&#xff0c;但碍于精力和篇幅限制决定将内容分几期&#xff0c;本期首先介绍DP&#xff0c;但并不是因为DP简单&#xff0c;相反DP的水也很深&…

LeeCode144二叉树的前序遍历

项目场景&#xff1a; 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 解释&#xff1a; 示例 2&#xff1a; 输入&#xff1a;root [1,2,3,4,5,null,8,null,null,6,7…

日本生活:日语语言学校-日语作文-沟通无国界(3)-题目:わたしの友達

日本生活&#xff1a;日语语言学校-日语作文-沟通无国界&#xff08;&#xff13;&#xff09;-题目&#xff1a;わたしの友達 1-前言2-作文原稿3-作文日语和译本&#xff08;1&#xff09;日文原文&#xff08;2&#xff09;对应中文&#xff08;3&#xff09;对应英文 4-老师…

使用 rsync 拉取文件(从远程服务器同步到本地)

最近在做服务器迁移&#xff0c;文件好几个T。。。。只能单向访问&#xff0c;服务器。怎么办&#xff01;&#xff01;&#xff01; 之前一直是使用rsync 服务器和服务器之间的双向同步、备份&#xff08;这是推的&#xff09;。现在服务器要迁移&#xff0c;只能单向访问&am…

Linux 并发编程:从线程池到单例模式的深度实践

文章目录 一、普通线程池&#xff1a;高效线程管理的核心方案1. 线程池概念&#xff1a;为什么需要 "线程工厂"&#xff1f;2. 线程池的实现&#xff1a;从 0 到 1 构建基础框架 二、模式封装&#xff1a;跨语言线程库实现1. C 模板化实现&#xff1a;类型安全的泛型…

2013年SEVC SCI2区,自适应变领域搜索算法Adaptive VNS+多目标设施布局,深度解析+性能实测

目录 1.摘要2.自适应局部搜索原理3.自适应变领域搜索算法Adaptive VNS4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流 1.摘要 VNS是一种探索性的局部搜索方法&#xff0c;其基本思想是在局部搜索过程中系统性地更换邻域。传统局部搜索应用于进化算法每一代的解上&…

详细介绍医学影像显示中窗位和窗宽

在医学影像&#xff08;如DICOM格式的CT图像&#xff09;中&#xff0c;**窗宽&#xff08;Window Width, WW&#xff09;和窗位&#xff08;Window Level, WL&#xff09;**是两个核心参数&#xff0c;用于调整图像的显示对比度和亮度&#xff0c;从而优化不同组织的可视化效果…

Unity_VR_如何用键鼠模拟VR输入

文章目录 [TOC] 一、创建项目1.直接创建VR核心模板&#xff08;简单&#xff09;2.创建3D核心模板导入XR包 二、添加XR设备模拟器1.打开包管理器2.添加XR设备模拟器3.将XR设备模拟器拖到场景中4.运行即可用键盘模拟VR输入 一、创建项目 1.直接创建VR核心模板&#xff08;简单&…

SpringBoot定时监控数据库状态

1.application.properties配置文件 # config for mysql spring.datasource.url jdbc\:mysql\://127.0.0.1\:3306/数据库名?characterEncoding\utf8&useSSL\false spring.datasource.username 账号 spring.datasource.password 密码 spring.datasource.validation-quer…

Qt联合Halcon开发一:Qt配置Halcon环境【详细图解流程】

在Qt中使用Halcon库进行图像处理开发&#xff0c;可以有效地结合Qt的图形界面和Halcon强大的计算机视觉功能。下面是详细的配置过程&#xff0c;帮助你在Qt项目中成功集成Halcon库。 步骤 1: 安装Halcon软件并授权 首先&#xff0c;确保你已经在电脑上安装了Halcon软件&#x…

一体化(HIS系统)医院信息系统,让医疗数据互联互通

在医疗信息化浪潮下&#xff0c;HIS系统、LIS系统、PACS系统、电子病历系统等信息系统成为医疗机构必不可少的一部分&#xff0c;从患者挂号到看诊&#xff0c;从各种检查到用药&#xff0c;从院内治疗到院外管理……医疗机构不同部门、不同科室的各类医疗、管理业务几乎都初步…

Spring Boot 的 3 种二级缓存落地方式

在高并发系统设计中&#xff0c;缓存是提升性能的关键策略之一。随着业务的发展&#xff0c;单一的缓存方案往往无法同时兼顾性能、可靠性和一致性等多方面需求。 此时&#xff0c;二级缓存架构应运而生&#xff0c;本文将介绍在Spring Boot中实现二级缓存的三种方案。 一、二…

Android Studio Profiler使用

一:memory 参考文献: AndroidStudio之内层泄漏工具Profiler使用指南_android studio profiler-CSDN博客

Zephyr boot

<!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>Zephyr设备初始化机制交互式解析…

腾讯地图Web版解决热力图被轮廓覆盖的问题

前言 你好&#xff0c;我是喵喵侠。 还记得那天傍晚&#xff0c;我正对着电脑调试一个腾讯地图的热力图页面。项目是一个区域人流密度可视化模块&#xff0c;我加了一个淡蓝色的轮廓图层用于表示区域范围&#xff0c;热力图放在下面用于展示人流热度。效果一预览&#xff0c;…

【JVMGC垃圾回收场景总结】

文章目录 CMS在并发标记阶段&#xff0c;已经被标记的对象&#xff0c;又被新生代跨带引用&#xff0c;这时JVM会怎么处理?为什么 Minor GC 会发生 STW&#xff1f;有哪些对象是在栈上分配的&#xff1f;对象在 JVM 中的内存结构为什么需要对齐填充&#xff1f;JVM 对象分配空…