• Linux:环境变量、地址空间


    目录

    一、环境变量

    1、什么是环境变量

    2、常见的环境变量

    3、环境变量相关命令 

    二、地址空间

    1、进程地址空间

    2、虚拟地址空间


    一、环境变量

    1、什么是环境变量

    首先先举个环境变量的例子:

    我们在Linux中,运行ls、pwd之类的命令,直接输入就能运行,输入路径/usr/bin/ls/pwd当然也能运行

    那我们有一个可执行文件test,为什么不能直接输入test运行,必须要输入./test或是它的具体路径才能运行,如下:

    其实很简单,因为像ls/pwd这些命令,是在环境变量path中已经配置过了,所以是默认可被找到的,如下图可见echo $path:环境变量前加$就可以看到里面内容

    里面的路径是用冒号分割开的

    可以看到里面有/usr/bin这个路径,而我们上面的pwd、ls都是在这个搜索路径当中

    而我们的可执行程序并不在环境变量的搜索路径中,所以我们也就没办法直接执行

    但是下面的export命令可以帮我们做到这一点


    2、常见的环境变量

    PATH:指定命令的搜索路径

    HOME:指定用户的主工作目录

    SHELL:当前的shell值,一般是/bin/bash


    3、环境变量相关命令 

    ①查看某个环境变量的值

    echo $[环境变量名字]

    ②查看全部环境变量

    查看当前系统全部的环境变量:env

    ③设置一个新的环境变量

    export

    执行export PATH=$PATH:/home/fcy/lesson后,再echo,就可以发现我们的/home/fcy/lesson这个路径,也被添加到搜索路径当中了

    ④清除环境变量

    unset

    ⑤显示定义本地的shell变量和环境变量

    set


    二、地址空间

    1、进程地址空间

    首先回顾一下,地址空间的布局如下图:

    下面用Linux验证一下地址空间的布局:

    运行结果:

    可以清楚看到,运行结果从上到下,分别是代码区,已初始化,未初始化,堆,栈

    从上面的分布图可以知道,代码区,已初始化,未初始化,堆,栈是从低地址到高地址存储的,所以运行结果也是从小到大的 


    我们也可以发现,堆和栈的差别是非常大的,因为堆是由低地址向高地址存储,而栈是由高地址向低地址存储的,所以他们中间相隔的地址是很大的

    下面验证堆是由低地址向高地址存储,而栈是由高地址向低地址存储的:

    我们malloc的数据时在堆中开辟的,所以变量p0、p1、p2、p3是在堆上的,而开辟出来的p0、p1、p2、p3变量的地址是存在栈上的

    结果如下:

    观察结果可以看到,堆从heap0到heap3是在递增的,而栈从stack0到stack3是递减的

    说明我们上面所说的堆是由低地址向高地址存储,而栈是由高地址向低地址存储的:

    堆栈相对而生


    static修饰的局部变量,本质就是将该变量开辟在全局区域

    下面的内存打印结果可以看出来:

    观察打印的地址可以看到,局部变量a1是栈里的,而a2前面加上了static,这时a2的地址就到了val与un_val那里得全局区域了

    这就是为什么static修饰的局部变量,它的生命周期是全局属性的


    2、虚拟地址空间

    我们要知道虚拟地址空间的存在,至于怎么证明这个虚拟地址空间是存在的,看下面的证明:

    有一个全局变量val,赋初始值为5,然后执行fork函数,有两个进程,分别进入if和else语句执行死循环,其中子进程在运行三次后,改变val的值,而父进程不改变,每次循环都打印val和val的地址

    结果如下:

    可以发现,在第四次循环后,子进程由于改变了val值,打印时val变为10,而父进程val仍为5,并且观察他们打印出来的val的地址,都是0x60103c

    这时我们可以明白,一个变量val,值不同,一个5一个10,反而val的地址却是相同的,所以这里打印出来的0x60103c肯定不是真实的物理地址,而是虚拟地址

    所以证明了虚拟地址空间的存在


    接下来用虚拟地址空间解释一下上面代码中出现的情况

    首先父子进程被创建,子进程继承了父进程的许多属性,所以他们的地址空间分布也基本一样,所以父子进程的val在虚拟地址空间中所处的位置也就相同,页表的映射关系也一样,所以父子进程的val打印出来的的虚拟地址相同

    而当子进程通过页表的映射关系,想要找到对应的物理地址改变自己的val值时,操作系统又会给给子进程的val重新开辟一段物理空间,并改变子进程页表的映射关系,这时虽然父子进程val的虚拟地址相同,但通过页表映射的物理地址却是不同的了

    所以做到了val值不同,打印出来的虚拟地址却是相同的

    这种情况就叫做写时拷贝


    那么为什么要有地址空间的存在呢?

    1、地址空间和页表都是OS创建并维护的,所以想要使用地址空间和页表进行映射,都是在OS的监管之下的,所以凡是非法的访问或者映射,OS都会识别到,并终止这个进程,从而有效的保护了物理内存

    2、地址空间的存在,可以将进程管理和内存管理通过页表进行解耦,两个模块互不影响,只需要通过页表建立映射关系即可

    3、以统一的视角看待所有的进程,在系统底层用页表映射到不同的物理内存处,完成进程独立性的实现


  • 相关阅读:
    【三种加载自定义控制器的方式 Objective-C语言】
    Vue框架学习大纲
    相似图像的检测方法
    实验08 软件设计模式及应用
    NewStarCTF 2023 web
    化工行业数字化供应链系统:赋能化工企业高质量发展,促进上下游协同
    R可视化:生存分析森林图
    前后端联调统一校验规则
    2023年【安全生产监管人员】考试报名及安全生产监管人员复审考试
    小程序源码:多功能喝酒神器-多玩法安装简单
  • 原文地址:https://blog.csdn.net/m0_64411530/article/details/133466923