Linux环境变量和进程地址空间


一、环境变量

1.1 基本概念

  • 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
  • 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
  • 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
  • 通常使用Java等语言时也需要配置环境变量

常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash。

和环境变量相关的命令

  1. echo: 显示某个环境变量值
  2. export: 设置一个新的环境变量
  3. env: 显示所有环境变量
  4. unset: 清除环境变量
  5. set: 显示本地定义的shell变量和环境变量

1.2 查看环境变量方法

echo $NAME //NAME:环境变量名称
在这里插入图片描述

1.3 测试环境变量

1.3.1 PATH

自己写一个程序,观察启动运行的方式
在这里插入图片描述
为什么make指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行?

命令、程序、工具等本质上都是一个文件,程序名不能直接执行程序的原因是系统不知道它的路径,命令等文件的路径系统是知道的,系统可以直接找到执行,那我们把程序的路径也放到环境变量中看一下是否可以直接执行。

将我们的程序所在路径加入环境变量PATH当中命令export PATH=$PATH:hello程序所在路径
在这里插入图片描述

我们的这种修改是只能作用本次登录的,所以不用担心弄错了。(建议文件夹也以字母开头,我开始以数字开头发现设置环境变量后系统找不到)

1.3.2 本地变量

系统上还存在一种变量,是与本次登陆(session)有关的变量,只在本次登陆有效,(本地变量)
在这里插入图片描述
在这里插入图片描述

1.3.3 测试HOME

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

1.4 main函数的三个参数

这是我们学习C语言时常见main的两个参数,它们分别表示什么意思,怎么用呢?

在这里插入图片描述

1.4.1 int argc 和 char* argv[ ]

argv字符指针数组:存放命令行的参数
argc: argv数组的大小

在这里插入图片描述

在这里插入图片描述
那么可以知道,第一个字符串是程序路径,固定了的

可以模仿指令,再后面增加选项,函数输出不同的内容
在这里插入图片描述
在这里插入图片描述

1.4.2 环境变量参数 char *env[]

这个参数我们不太熟悉,因为这个参数是由系统自动传进去的。

测试一下里面存放了什么内容,既然没有给定的长度,那应该末尾有结束标识符空。

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

是否很熟悉,没错就是我们使用env打印出来的环境变量。

还可以通过getenv()打印特定的环境变量

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

1.5 环境变量具有全局属性

环境变量通常具有全局属性,可以被子进程继承下去
在这里插入图片描述

在这里插入图片描述

二、进程地址空间

2.1 C/C++程序地址空间

先来看一下C/C++语法层面上认为的内存空间分布
在这里插入图片描述

我们可以使用程序来验证一下,具体是不是这样排布的

  #include<stdio.h>    
  #include<stdlib.h>                                                 
  int g_unval;//未初始化的全局变量    
  int g_val;//初始化的全局变量    
  int main(int argc, char* argv[],char* env[])    
  {    
    printf("code adder:%p\n",main);//代码区    
    const char* s = "hello,world";    
    printf("string readonly  adder:%p\n",s);//字符常量区    
    printf("uninit adder:%p\n",&g_unval);//字符常量区    
    printf("init adder:%p\n",&g_val);//字符常量区    
    char* heap = (char*)malloc(10);    
    char* heap1 = (char*)malloc(10);    
    char* heap2 = (char*)malloc(10);    
    char* heap3 = (char*)malloc(10);    
    char* heap4 = (char*)malloc(10);    
    printf("heap adder:%p\n",heap);//堆区    
    printf("heap1 adder:%p\n",heap1);    
    printf("heap2 adder:%p\n",heap2);    
    printf("heap3 adder:%p\n",heap3);  
    printf("heap4 adder:%p\n",heap4);
    printf("stack1 adder:%p\n",&s);
    printf("stack2 adder:%p\n",&heap);
    printf("stack3 adder:%p\n",&heap1);
    int a = 10;
    printf("stack4 adder:%p\n",&a);
    int i;
    //环境变量区
    for(i = 0; i<argc; ++i)
    {
      printf("argv[%d]:%p\n",i,&argv[i]);
    }
    for(i = 0; env[i]; ++i)                                          
    {
      printf("env[%d]:%p\n",i,&env[i]);
    }
    return 0;
  }

在这里插入图片描述
结果也确实如此,地址大小有顺序。

2.2 进程地址空间

现在来做一个实验,验证一下C/C++程序地址空间是否是真的物理内存

在这里插入图片描述

我们知道子进程进程父进程的代码和数据,创建属于自己的PCB,不修改数据的话两个是用同一段空间,但是如果数据发生修改,就会发生写时拷贝。

但是惊奇的发现父子进程的a变量的地址是一样的,是怎么回事呢?
在这里插入图片描述

可以的到结论:

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  • 但地址值是一样的,说明,该地址绝对不是物理地址!
  • 在Linux地址下,这种地址叫做 虚拟地址
  • 我们在用C/C++语言所看到的地址,全部都是虚拟地址!
  • 物理地址,用户一概看不到,由OS统一管理

2.3 页表

OS为每一个进程分配一个与物理内存分布相同的虚拟地址空间,让每一个进程都认为自己独享内存。OS对进程地址空间也是通过结构体来描述的Linux下是:struct mm_struct。
里面存放对内存划分的数据,让进程将不同的数据放在不同的空间。但是不管怎样数据最终都是存在物理内存上的,那OS是通过什么来实现的呢?

答案是页表,每个进程都有一个自己的虚拟地址空间,然后通过页表来与真实的物理空间对应,它们通过页表的映射,来存放数据。

在这里插入图片描述

2.4 为什么要有进程地址空间

  1. 通过添加一层软件层,完成有效的对进程操作内存进行风险管理(权限管理),本质目的是为了,保护物理内存以及各个进程的数据安全!
  2. 将内存申请和内存使用的概念在时间上划分清楚,通过虚拟地址空间,来屏蔽底层申请内存的过程,达到进程读写内存和OS进行内存管理操作,进行软件上面的分离!
  3. 站在CPU和应用层的角度,进程统一可以看做统一使用4GB(32位)空间,而且每个空间区域的相对位置,是比较确定的。这样方便CPU和系统的查找和使用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s_persist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值