当前位置: 首页 > news >正文

进程地址空间

目录

  • 1.进程地址空间
    • 1.进程地址空间认证
    • 2.如何理解static变量
    • 3.当父子进程没有人修改全局数据的时候父子是共享数据的,但是如果尝试写入了?
    • 4.为什么操作系统不给我们直接看到物理地址
    • 5.进程地址空间到底是什么?
    • 6.程序被编译的时候,没有被加载的时候,由地址吗?有区域吗?
    • 7.为什么要有虚拟内存空间

1.进程地址空间

在这里插入图片描述

1.进程地址空间认证

代码

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


int un_g_val;
int g_val=100;

int main(int argc, char *argv[], char *env[])
{
    printf("code addr         : %p\n", main);
    printf("init global addr  : %p\n", &g_val);
    printf("uninit global addr: %p\n", &un_g_val);
    char *m1 = (char*)malloc(100);
    char *m2 = (char*)malloc(100);
    char *m3 = (char*)malloc(100);
    char *m4 = (char*)malloc(100);
    static int s = 100;
    printf("heap addr         : %p\n", m1);
    printf("heap addr         : %p\n", m2);
    printf("heap addr         : %p\n", m3);
    printf("heap addr         : %p\n", m4);

    printf("stack addr        : %p\n", &m1);
    printf("stack addr        : %p\n", &m2);
    printf("stack addr        : %p\n", &m3);
    printf("stack addr        : %p\n", &m4);
    printf("s stack addr        : %p\n", &s);
    int i=0;
    for( i = 0; i < argc; i++)
    {
        printf("argv addr         : %p\n", argv[i]); //argv/&argc?
    }
    
    for( i =0 ; env[i];i++)
    {
        printf("env addr          : %p\n", env[i]);
    }
}

在这里插入图片描述
可以看到上面的代码和前面我的发的图分布是
堆区向地址增大方向增长,栈区向地址减少方向增长
栈,我们一般在c函数定义的变量,通常都在栈上保存,那么先定义的一定是地址比较高的

2.如何理解static变量

c语言中我们了解到:如果一个变量在函数里定义声明为static,它的作用域不变,但是它的生命周期会随着程序一直存在
眼尖的上面的图片就已经看到了
在这里插入图片描述
s被修饰成了static是时候他的地址也发生了改变

3.当父子进程没有人修改全局数据的时候父子是共享数据的,但是如果尝试写入了?

代码

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

int g_val=100;

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        int flag = 0;
        while(1)
        {
            printf("我是子进程:%d, ppid: %d, g_val: %d, &g_val: %p\n\n", getpid(), getppid(), g_val, &g_val);
            sleep(1);
            flag++;
            if(flag == 5)
            {
                g_val=200;
                printf("我是子进程,全局数据我已经改了,用户你注意查看!\n");
            }
        }
    }
    else 
    {
        //parent
        while(1)
        {
            printf("我是父进程:%d, ppid: %d, g_val: %d, &g_val: %p\n\n", getpid(), getppid(), g_val, &g_val);
            sleep(2);
        }
    }
}

运行结果
在这里插入图片描述
可以看到父子进程读取同一个变量(因为地址一样),但是后续没有人修改的情况父子进程读取的内容却不一样
如果是物理地址是不可能出现这种情况的,所以上面的不是物理地址,而是虚拟地址,也被称为线性地址

上面那种情况相当于
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰

比如有个操作系统是个富豪他有10亿家产
而他有三个进程是他的儿子
富豪就给三个儿子画饼,说给每个儿子10个亿
但是因为不是马上拿10个亿的,因为它们根本用不了10个亿那么多,而是一点一点拿,而进程地址空间的作用就是让每个进程都拥有独立的资源

4.为什么操作系统不给我们直接看到物理地址

内存是一个硬件,不能阻拦你访问,只能被动的进行读取和写入,如果你能访问的话,那你就能随便的用指针来访问了,这样子就有可能一个进程越界改变了其他进程,甚至改变了操作系统的数据,导致整个系统都崩了

每一个进程在启动的时候,都会让操作系统给他创建一个地址空间,这个地址空间是进程地址空间,操作系统是要管理这些进程地址空间的,先描述,在组织,进程地址空间,其实是内核的一个数据结构,stuct mm_struct

5.进程地址空间到底是什么?

所谓的地址空间:其实就是操作系统通过软件的方式,给进行提供一个软件视角,认为自己会独占系统的所有资源

在这里插入图片描述

大概简略是这样的有个页表区分区域来分别存放虚拟地址和物理地址,建立映射关系,可以通过虚拟地址来访问到物理地址
而页表的产生是:将程序加载到内存有程序变成进程之后,由操作系统会给没一个进程构建一个页表结构

6.程序被编译的时候,没有被加载的时候,由地址吗?有区域吗?

答案:是有地址的,还记得链接吗?链接是把我们的程序和库产生关联,但是你没有地址怎么链接啊?
而区域也是有的
readelf -S 文件
在这里插入图片描述
那么可能有点懵了,因为没有被加载的时候都有地址了,那么加载的时候在干什么,这二个地址有什么关系
比如 我在一个跑道里,左边是0,右边是100米,我现在是在30米的地方,这个是绝对地址,我傍边有棵树离我5米,这是相对地址,那么不管我左边或者右边的刻度怎么改变,变成100也好200也好,我和树的距离都不会发生改变,而这种相对地址可以理解成和程序开始的相对地址

这个时候我们就能回答之前的问题了,为什么地址一样,但是父子进程打印不同的值,是因为它们的虚拟地址相同,但是物理地址不同了,因为进程具有独立性
当我们子进程想要发生修改,那么操作系统就会给子进程重新开辟一段空间,并且把他的数据写实拷贝下来,重新给子进程建立新的映射关系,也就是改页表的右侧,不改左侧虚拟地址,所以才看到地址相同,但是数据不同

7.为什么要有虚拟内存空间

访问内存添加了一层软硬件层,可以对转化过程进行审核,非法的直接被拦截
1.可以保护内存
2.进程管理
通过地址空间,进程功能模块的解耦
3.让进程或者程序可以以一种统一的视角来看待内存
方便以统一的方式来编译或加载所有的可执行文件
简化进程本身的设计和实现

相关文章:

  • 接口与接口间怎样通过嵌套创造出新的接口?
  • HFCTF-2021-Final-easyflask
  • 神经网络系统技术是什么,神经网络系统技术应用
  • java+SpringBoot+HTML+Mysq基于微信小程序的大咖读书系统的设计与实现
  • 前端周刊第三十四期
  • Maven私服搭建与使用:nexus,repository,mirror,distributionManagement
  • ubuntu22.04安装Kubernetes1.25.0(k8s1.25.0)高可用集群
  • 高等教育学:技能的形成
  • 快来看,数据分析BI软件居然也能完成基金变迁大数据分析?
  • 16.线程通信1:生产者/消费者问题
  • SpringBoot校园二手书管理系统
  • 初识Nginx + Linux 中安装Nginx
  • 关于 SAP UI5 控件的 Densities 话题讨论
  • 禁忌搜索算法TS求解连续函数最值
  • 分布式精讲系列 实现分布式服务应该具备哪些核心技术组件?
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • Android 控件背景颜色处理
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • LeetCode算法系列_0891_子序列宽度之和
  • socket.io+express实现聊天室的思考(三)
  • Terraform入门 - 1. 安装Terraform
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • vue-cli3搭建项目
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 利用DataURL技术在网页上显示图片
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 【干货分享】dos命令大全
  • 阿里云ACE认证之理解CDN技术
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​TypeScript都不会用,也敢说会前端?
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • # 达梦数据库知识点
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • %check_box% in rails :coditions={:has_many , :through}
  • ()、[]、{}、(())、[[]]命令替换
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (c语言)strcpy函数用法
  • (JS基础)String 类型
  • (Oracle)SQL优化技巧(一):分页查询
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (力扣题库)跳跃游戏II(c++)
  • (原創) 未来三学期想要修的课 (日記)
  • .htaccess配置重写url引擎
  • .NET MVC之AOP
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET命令行(CLI)常用命令
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [20150904]exp slow.txt
  • [Big Data - Kafka] kafka学习笔记:知识点整理
  • [BROADCASTING]tensor的扩散机制
  • [BUUCTF]-PWN:wustctf2020_number_game解析(补码,整数漏洞)