Linux-程序地址空间

目录

 1. 程序地址空间分布

2. 两个问题

3. 虚拟地址和物理地址

4. 页表

5. 解决问题

6. 为什么要有地址空间


 1. 程序地址空间分布

测试一下: 

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>int gal_init = 1;
int gal_uninit;int main(int argc, char* argv[], char* env[])
{printf("code add:%p\n",main);const char* str = "hello";printf("str add:%p\n",str);printf("init global add:%p\n",&gal_init);printf("uninit global add:%p\n",&gal_uninit);char* heap1 = (char*)malloc(10);char* heap2 = (char*)malloc(10);char* heap3 = (char*)malloc(10);char* heap4 = (char*)malloc(10);printf("heap1 add:%p\n",heap1);printf("heap2 add:%p\n",heap2);printf("heap3 add:%p\n",heap3);printf("heap4 add:%p\n",heap4);printf("stack1 add:%p\n",&heap1);printf("stack2 add:%p\n",&heap2);printf("stack3 add:%p\n",&heap3);printf("stack4 add:%p\n",&heap4);int i = 0;for(;i < argc; ++i){printf("%s:%p\n",argv[i],&argv[i]);}printf("env add:%p\n",env);return 0;
}

运行结果:

code add0x40057d
int a add0x7ffc2b16df7c
static int b add0x601044
str add0x40081d
init global add0x60103c
uninit global add0x601048
heap1 add0x2301010
heap2 add0x2301030
heap3 add0x2301050
heap4 add0x2301070
stack1 add0x7ffc2b16df70
stack2 add0x7ffc2b16df68
stack3 add0x7ffc2b16df60
stack4 add0x7ffc2b16df58
./myproc0x7ffc2b16e078
env add0x7ffc2b16e088

这些都是之前就了解过的内容,今天详细聊聊地址空间

2. 两个问题

1. 安全问题:

这些程序都在同一个地址空间中,如果发生了越界访问,野指针问题,这些问题该怎么办?

2. 一个特殊现象问题:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>int main()
{int num = 0;int ret = fork();if(ret == 0){int i = 3;while(i--){printf("I am child,num = %d,&num = %p\n",num,&num);sleep(1);                }num = 1;while(1){printf("I am child,num = %d,&num = %p\n",num,&num);sleep(1);}}else{while(1){printf("I am father,num = %d,&num = %p\n",num,&num);sleep(1);}}return 0;
}

为什么父进程和子进程中的num同一个地址,但是却有两个值?

3. 虚拟地址和物理地址

在Linux地址下,这种地址叫做 虚拟地址

我们在用C/C++语言所看到的地址,全部都是虚拟地址!

物理地址,用户一概看不到,由OS统一管理

由OS负责将 虚拟地址 转化成 物理地址 

上面的地址空间分布就是虚拟地址,每个进程被创建,就会有对应的虚拟地址表

虚拟地址表在linux下就是由mm_struct结构体来描述的

Linux下的进程管理PCB:task_struct就有一个指针指向mm_struct,程序和虚拟地址空间联系起来了

4. 页表

OS是如何把虚拟地址转换成物理地址的呢?

页表

页表是一种key-value的数据结构,记录虚拟地址和物理地址一一映射关系

task_struck有一个指针指向页表

页表里的值(虚拟地址,物理地址)是哪里来的呢?

代码在被编译器编译后的每一条语句每一个函数都会有对应的地址,这个地址是逻辑地址,和虚拟地址一样,作为页表的虚拟地址。当程序被加载到物理内存中时,就会有对应的物理地址,然后在对应到页表里面。

程序被执行时,使用的地址是虚拟地址,需要用页表映射到物理地址 

5. 解决问题

到这里,我们就可以解决第一个问题,每个进程都有一个虚拟地址和页表,这些都由OS来维护,在页表对应的每一个物理地址后面,都有一个像文件访问权限一样的标志,如果这个物理地址没有访问权限,就会直接报错终止。有效的保护了物理内存。

第二问题的答案就在图中,fork函数创建子进程时,其实就是拷贝了大部分对应的task_struct,mm_struct和页表,因为父子进程之间大部分属性都一样,但当需要改变num的值时,子进程就在物理空间上重新开了一块空间,拷贝父进程,OS也会更新对应的页表映射关系。这个叫做写时拷贝。但是虚拟地址还是一样的,只是映射关系发生了变化。所以num相同的虚拟地址,不同的值。

6. 为什么要有地址空间

安全性,有效的保护了物理内存

因为地址空间和页表是OS创建并维护的,凡是想用地址空间和页表进行映射,都需要在OS的监管下来进行访问。

内存管理模块和进程管理模块完成了解耦

提高内存的利用率

用户申请的物理空间,malloc和new其实是在虚拟地址上申请的,OS通过延迟分配,提高物理内存的利用率

地址空间和页表的存在可以将内存分布有序化(按照地址空间分布)和进程的独立性(不同的进程映射到不同的物理空间)每一个进程不知道其他进程的存在

对于程序的分批加载,当程序刚刚新建的状态下,进程就只创建内核结构,程序和数据还没有加载到内存中。

程序的分批换出,当进程短时间内不会再被执行了,比如阻塞了,进程的数据和代码被换出到磁盘中的swap区,页表的映射关系也改为磁盘地址。这个过程就叫挂起。

完,写的不好的地方多有体谅,还在学

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

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

相关文章

【Windows11】cmd下运行python弹出windows应用商店解决方案

【Windows11 】cmd下运行python弹出windows应用商店解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇【Windows11 】cmd下运行python弹出windows应用商店解决方案✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天在安装python时&#xff0c;在命令行窗口输入如下命令&a…

C语言 | Leetcode C语言题解之第9题回文数

题目&#xff1a; 题解&#xff1a; bool isPalindrome(int x) {if(x < 0)return false;long int sum0;long int nx;while(n!0){sumsum*10n%10;nn/10;}if(sumx)return true;elsereturn false; }

45.网络游戏逆向分析与漏洞攻防-角色管理功能通信分析-解码发送数据内容输出到日志

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 现在的代码都是依据数据包来写的&#xff0c;如果看不懂代码&#xff0c;就说明没看懂数据包…

蓝桥备赛——循环+二分

题干 AC code n,kmap(int,input().split()) data[] for i in range(n):h,wmap(int,input().split())mid[]mid.append(h)mid.append(w)data.append(mid) front,tail1,100000 def find(edge_len):global kans0for wid,hei in data:ans(wid//edge_len)*(hei//edge_len)if ans>…

用 Wireshark 解码 H.264

H264&#xff0c;你不知道的小技巧-腾讯云开发者社区-腾讯云 这篇文章写的非常好 这里仅做几点补充 init.lua内容&#xff1a; -- Set enable_lua to false to disable Lua support. enable_lua trueif not enable_lua thenreturn end-- If false and Wireshark was start…

DeepWalk论文翻译

DeepWalk论文翻译 DeepWalk: Online Learning of Social Representations DeepWalk&#xff1a;社会表征的在线学习 ABSTRACT 我们提出了 DeepWalk&#xff0c;一种学习网络中顶点潜在表示的新方法。这些潜在表示在连续向量空间中对社会关系进行编码&#xff0c;很容易被统…

网站上的图片显示不清晰的解决办法!

1.图片搞上去。图片png格式显示不出来。 upload文件夹里。图片没上传。 2.显示的图片不够清晰。 productDescription.css height: 250px; width: 200px; 显示的图片大小是宽200&#xff0c;高250&#xff0c; 所以在windows的画图工具里用画图把像素成这个像素大小的清…

基于Spring Boot的职称评审管理系统

基于Spring Boot的职称评审管理系统 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 部分系统展示 前台首页界面 用户注册登录界面 管理员登录界面 个人中心界面…

(React组件基础)前端八股文修炼Day6

一 类组件与函数组件有什么异同 在React中&#xff0c;类组件和函数组件是创建组件的两种主要方式。随着React的发展&#xff0c;尤其是自Hooks在React 16.8中引入以来&#xff0c;函数组件的功能变得更加强大&#xff0c;使得它们能够更加方便地与类组件相竞争。下面是类组件…

鲍威尔最新演讲:今年仍有降息空间

作者&#xff1a;秦晋 4月3日&#xff0c;据《华尔街日报》报道&#xff0c;鲍威尔仍然认为美联储今年有降息空间。 美联储主席鲍威尔周三在斯坦福大学发表演讲时表示&#xff0c;今年的经济活动强于预期并没有改变美联储的广泛预期&#xff0c;即通胀下降将允许美联储在今年降…

gitcode 配置 SSH 公钥

在 gitcode 上配置SSH公钥后&#xff0c;可以通过SSH协议安全地访问远程仓库&#xff0c;无需每次都输入用户名和密码。以下是配置SSH公钥的步骤&#xff1a; 5分钟解决方案 用 OpenSSH公钥生成器 生成 公钥和私钥&#xff0c;私钥文件&#xff08;id_rsa&#xff09;下载&am…

代码随想录阅读笔记-二叉树【二叉搜索树中的众数】

题目 给定一个有相同值的二叉搜索树&#xff08;BST&#xff09;&#xff0c;找出 BST 中的所有众数&#xff08;出现频率最高的元素&#xff09;。 假定 BST 有如下定义&#xff1a; 结点左子树中所含结点的值小于等于当前结点的值结点右子树中所含结点的值大于等于当前结点的…