环境变量&&进程地址空间

一. 环境变量

1.浅谈环境变量

在命令行上输入对应的指令就可以实现相应的内容,我们知道,其实这些命令的执行就是一个又一个进程的执行,因为系统的命令,程序,工具什么的对应语句都是一些可执行文件,在命令行上直接输入然后他就可以执行。

比如:

cd .. 就是返回上一级目录。
pwd 就是显示当前路径

但是为什么我们自己编写的文件需要 ./ 加上可执行文件来执行呢?
答:帮系统确认程序在哪里,是为了找到文件对应的路径。

为什么系统中的命令不需要找到路径再执行呢?-> 环境变量之PATH
对应指令:

echo $PATH,查看环境变量的内容。

实现如下:
在这里插入图片描述

我们发现所有的路径都以 : 进行路径分割
":"是用来进行分割各种路径,在相应的路径下找到文件就可以执行。
那么如何让可执行文件像命令一样直接执行呢?

  1. 将文件考入文件路径中。
  2. 将文件路径拷贝到环境变量当中。
    但是并不是很推荐,因为这样会污染既定好的环境变量池,造成混乱。
//export 将可执行文件的路径导入环境变量。

在这里插入图片描述
在这里插入图片描述

2. 什么是环境变量

上文说介绍了一个环境变量PATH,还有一个环境变量: HOME。

echo $HOME:用户的主工作目录

经检验,每一个用户的家目录都不一样。
为什么不同的用户他的家目录不一样?
默认路径不同。
命令:

  1. 语言上面定义变量本质上是在内存中开辟空间(有名字),我们不要质疑OS开辟空间的能力。
  2. 环境变量本质上是 OS在内存或者磁盘上开辟空间,用来保存系统相关的数据。
  3. 环境变量无非就是 变量名+变量内容
echo :
set:设置查找本地或者环境变量
uset: 取消本地或者环境变量
env: 查看环境变量的内容
  1. 本地变量:系统上还存在一种变量,是只和本次登录有关的变量,只在本次登陆有效(本地变量)
    在这里插入图片描述

  2. export:将本地变量导入环境变量。
    注释:本地变量用env是查不到的。export之后就可以了。
    在这里插入图片描述

3. 命令行参数

比如:C语言中的main函数是可以携带参数的。

int main(int argc,char* argv[],char* env[])

传过来的参数都放在argv指针数组当中,argc是数组个数。
指针数组是以NULL进行结尾的。
env[]是一个存放环境变量的地址的数组,存储方式和argv[]是类似的。
在这里插入图片描述

为什么要有命令行参数?
经测试显示:
指令有很多选项,用来完成同一个命令的不同子功能,选项底层使用的就是我们的命令行参数。但是我们经常使用的VS当中是没有命令行的。
有命令行我们就可以实现如下类似操作:
sort 选择排序指令。
sort - q ; 直接进行快速排序排序函数的操作就行了。
sort - b;选择归并排序的函数就行。
类似如下演示:
在这里插入图片描述

4.如何获取环境变量?

第一种:main函数的第三个参数就是 char* env[]环境变量。
我们可以像访问数组元素一样,获取这个数组当中的环境变量。
第二种:环境变量的处存方式和命令行参数基本一样。都是char* arr[]; 指针数组。
在这里插入图片描述

第三种:用 getenv(“环境变量名”);#include<stdlib.h>
在这里插入图片描述

5. 环境变量具有全局性,是因为环境变量是可以被子进程继承的。

那么如何证明呢? 如下演示(可能有点乱,请耐心逐语句理解注释):
在这里插入图片描述

继承的环境变量,之后的每个进程都可以获得。
gcc gdb 为什么可以直接联系到各种库?就是继承了-bash各种环境变量
注: 1. 命令行上启动的进程,父进程都是bash。
2. 函数如果没有参数,系统可以传参吗?可以。传参参数要用可变参数列表。

二. 进程地址空间

思路:

1. 内存存储的方式:上面是高地址,下面是低地址。

从低地址到高地址进行存放。堆区向上增加,栈区向下增加。
堆,栈,堆栈是栈。
在这里插入图片描述
在这里插入图片描述

2. C/C++程序地址空间,他是内存吗?

解答:不是内存(以前是按照内存理解)
那是啥啊?
验证程序地址空间。验证数据是像图标表示一样存储的,如上两个图。

观察下面的演示:
在这里插入图片描述

我们发现,父子进程中的同一变量数据已经改变而地址竟然没有发生变化,
所以我们这里使用的地址绝对不是物理地址,而是
虚拟地址。在语言层面上基本都是虚拟地址。
所以C/C++的刚才验证的程序地址空间,是进程虚拟地址空间。

3. 虚拟内存初步

进程地址空间:虽然叫进程地址空间但是绝对不是物理内存,而是虚拟内存。

  1. 每个进程都有一个地址空间,都认为自己在独占物理内存,类似于一个家族的每个儿子都认为自己可以继承全部的家产,并且依据家产做出自己的未来规划。
  2. 富翁画饼的目的是统一的方式组织进程。
  3. 先描述再组织这些很多的进程的地址空间。而OS,
    描述用结构体mmstruct{} 也就是画的大饼以及你的想法,在内核中是一个数据结构,具体的地址空间变量。
    上文中的C/C++程序地址空间都是在这个结构体当中。

4. 如何使用struct结构体进行各种区域划分,各种区域划分有什么物理意义?

  1. 每一个进程都可以以类似的方式规划整个内存空间。
  2. 地址空间本质上就是内核中的一种数据类型
    mm_struct{}就是内张饼,4GB大小。
  3. 例2:
    别人给我们画大饼,是可以通过数据的形式画的,银行余额。
    也是一种地址空间的概念。OS以数据形式给进程画一张饼。
    例3:
    “韩朝38线”的存在就是为了划分区域。能否用C语言描述这种场景?
    就是结构体演示一下:
struct{//整形的开始和结束来确定范围
	int start;
	int end;
	}

所有的活动都应该放在指定刻度范围(虚拟地址)当中,可以抽象出一个尺子对应范围。
4. 虽然每个进程都有start 和end进行边界划分,但是
每个进程都可以认为mm_struct 代表整个内存,且所有的地址为
0x000000~0xFFFFFF.每个进程都认为空间给自己的划分标准是按照4GB的空间进行划分的。
5. 地址空间上进行区域划分时,对应的线性位置,叫做虚拟地址(线性地址)。
6.
所以每个进程都有自己独立的PCB和地址空间mm_struct{}。
宽度是1字节,大小是4* 1024* 1024 * 1024个字节大小。

5. 虚拟地址和物理结构之间的联系

依靠 页表 + MMU(查页表CPU中)
页表类似下面正常表格:
在这里插入图片描述

左侧是虚拟地址,右侧是物理地址。将虚拟地址转化为物理地址,本身就是一个映射表。

6. 为什么非得有虚拟地址和页表进行映射物理内存呢?

  1. 在问这个问题之前,那我们如何保证task_struct一定会准确使用相应内存不造成越界问题呢?
    所以在中间加入一个中间软件层,就是虚拟地址,OS的代表。有效做到内存权限管理。
    如果出现错误会及时做出禁止。
  2. 字符串不可被修改的根本原因是
    语言上面理解是指针在栈区,字符串在字符常量区,不让发修改
    本质上是OS通过页表给你的权限只有r权限。不让你改。

7. 为什么要有地址空间?

  1. 通过添加一层软件层,完成有效的对进程内存进行风险管理。本质目的是为了保护物理内存以及各个进程的数据安全。
    思考,我们申请了1000个字节,我们马上就能够使用1000个字节吗?
    不一定,可能会存在不会暂时全部使用的情况。
    在操作系统角度如果立马给你内存,就会有一部分内存被闲置了。
    所以:先答应你开好内存了,等到你需要的时候再给你在物理内存上真正给你开辟空间。

  2. 将内存申请和使用的概念在时间上划分清除,通过虚拟地址空间,来屏蔽底层申请内存的过程,
    达到进程读写内存和OS进行内存管理操作,进行软件上的分离。
    OS做的内存申请动作是透明的,我们是不知道的。

  3. 可以统一的视角看待进程。
    CPU是怎么知道代码的起始入口的呢?
    地址空间映射使得每个进程的CPU读取都从地址空间的
    所以,站在CPU和应用层的角度出发,进程统一可以看做统一使用4GB空间,而且每个空间区域的相对位置是比较确定的。
    可以实现一个进程的各个部分在虚拟地址上,一个进程的各个部分在一起。但是在物理内存上可以是不连续的。大大提高了存储管理的消耗
    目的:每个进程能都认为自己独占内存资源空间。

以上三个就是原因,接下来我们来总结一下为什么父子进程的值是不一样的,而地址是一样的呢?:
子进程的创建是以父进程为模板的,父子进程打印的值是相等的,
代码是共享的,虚拟地址映射的是一块区域就行。
所以父子进程改变的全局变量值改变但是地址不变,不变的是虚拟地址。

所以,所有只读的数据,一般只有一份共享的。
OS维护一份,是成本最低的。两个指针指向同一块字符串常量内存空间。

后来父进程发生值的更改的时候,发生写时拷贝在物理内存中,但是虚拟地址现在仍然是一样的。值不一样本质原因
是在物理内存当中的位置本来就是不一样的,只不过虚拟内存同一块然后建立了两个映射关系。

8. 补充说明:

经代码验证:
argv[i]命令函参数在栈的上面,env[i]环境变量在更上面。
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值