Linux环境变量与进程虚拟地址空间

环境变量与地址虚拟空间

文章目录

      • 1.概念
      • 2.常见的环境变量与查看当前环境变量方法
      • 3.环境变量对应的文件
      • 4.修改环境变量
      • 5.环境变量的组织方式
      • 6.代码获取环境变量
        • 1.main函数的参数:
        • 2.通过第三方变量environ获取
        • 3.通过getenv
      • 7.C语言中的程序地址空间图
      • 8.虚拟地址
      • 9虚拟地址空间
      • 10.页表

1.概念

环境变量是指操作系统中用来指定操作系统运行的一些参数,换句话说,操作系统通过环境变量来找到运行时的一些资源
例如:链接时帮助连接器找到动态库,执行ls命令时帮助用户找到位置。

2.常见的环境变量与查看当前环境变量方法

  • PATH:指定可执行程序的搜索路径,程序员执行的命令之所以能找到,它功不可没
  • HOME:登录到LInux操作系统的用户家目录
  • SHELL:当前的命令行解释器,默认是“/bin/bash”

查看方法:

echo $[环境变量名称]
env:查看所有的环境变量
unset:清除环境变量
set:显示本地定义的shell变量与环境变量

3.环境变量对应的文件

  • 系统级文件:针对各个用户都起作用(仅root用户修改),强烈不建议修改,影响其他用户(/etc/bashrc);
  • 用户级环境变量文件:只对自己的环境变量做出修改(~/.brshrc , ~/.bash_profile , ~/.bash_profile 包含 ~/.bashrc包含 ~/.etc/bashrc)

4.修改环境变量

命令行中修改:

新增:export 环境变量名称=[新添加的环境变量内容]
例如:在这里插入图片描述

修改:export 环境变量名称=[$环境变量名称] [新添加的环境变量内容](echo $path:打印变量的内容)

在这里插入图片描述
注意:

  • 如果修改老的环境变量,必须加[$环境变量名称],否则之前的环境变量就找不到了
    例如:在这里插入图片描述
  • 在当前命令中添加的环境变量,生命周期跟随当前终端,当前终端如果退出了,环境变量就没有了,即临时有效

文件中修改:

修改完毕后不会立即生效,需要配合source [环境变量名称] 才可以永久生效
新增:在文件末尾直接添加: export环境变量名称=[新添加的环境变量的内容]
如果修改老的:在老的后面添加“:[新添加的环境变量的内容]”

5.环境变量的组织方式

环境变量是以字符指针数组的方式进行组织的,最后的元素以NULL结尾(即程序读取环境变量到NULL就结束)
如图:

Linux环境变量与进程虚拟地址空间_第1张图片

6.代码获取环境变量

1.main函数的参数:

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

例如在LINUX下运行如下程序

#include 
int main(int argc, char *argv[], char *env[])
{
 	int i = 0;
 	for(; env[i]; i++){
 	printf("%s\n", env[i]);
 }
 	return 0;
}

得到结果
Linux环境变量与进程虚拟地址空间_第2张图片

2.通过第三方变量environ获取

#include 
int main(int argc, char *argv[])
{
 	extern char **environ;
 	int i = 0;
 	for(; environ[i]; i++){
 	printf("%s\n", environ[i]);
 }
 	return 0;
}

3.通过getenv

#include 
#include 
int main()
{
 	printf("%s\n", getenv("PATH"));
 	return 0;
}

7.C语言中的程序地址空间图

Linux环境变量与进程虚拟地址空间_第3张图片

8.虚拟地址

通过两段代码比较得出结论:

#include 
#include 
#include 
int g_val = 0;
int main()
{
 	pid_t id = fork();
	if(id < 0){
 	perror("fork");
 	return 0;
 }
 	else if(id == 0){ //child
 		printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }else{ //parent
 		printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }
 	sleep(1);
 	return 0;
}
#include 
#include 
#include 
int g_val = 0;
int main()
{
 	pid_t id = fork();
 	if(id < 0){
 	perror("fork");
 	return 0;
 }
 	else if(id == 0){ //child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
 		g_val=100;
 		printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }else{ //parent
 	sleep(3);
 	printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
 }
 	sleep(1);
	return 0;
}

我们发现,父子进程,输出地址是一致的,但是变量内容不一样!能得出如下结论:

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

9虚拟地址空间

Linux环境变量与进程虚拟地址空间_第4张图片

10.页表

  • 映射关系:虚拟地址空间分成一页一页,物理内存分成一块一块,使用页表将页和块映射起来
  • fork创建子进程的时候,每个进程都有自己的页表,子进程最初的页表映射的内容就是来自于父进程,后面子进程在运行的时候,可能就会有不同的映射关系写道自己的页表中
  • 通过虚拟地址+页表的方式找到具体的物理地址:
    虚拟地址=页号+页内偏移
    页号=虚拟地址/页的大小
    页内偏移=虚拟地址%页的大小
  • 内存分配时采用离散分配的方式,不采用连续分配的方式防止内存碎片

你可能感兴趣的:(Linux,linux)