Linux进程----环境变量与程序地址空间

这篇博客详细介绍了Linux中的环境变量,包括其基本概念、常见环境变量、设置与查看方法,以及环境变量如何被子进程继承。此外,还探讨了程序地址空间,解析了进程虚拟地址空间的概念,讲解了存储器管理方式如分页、分段和段页式,以及进程优先级的原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境变量

一、基本概念
  1. 一般是指在操作系统中用来指定操作系统运行环境的一些参数;
  2. 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
二、常见环境变量
  1. PATH:查看可执行程序的环境变量;
  2. HOME:指定用户的主工作目录;
  3. SHELL:保存当前所使用的shell得到的环境变量,它的值通常是/bin/bash;
  4. LD_LIBRARY_PATH:程序运行时,库文件的搜索路径的环境变量;
  5. LIBRARY_PATH:程序编译时,库文件的搜索路径和环境变量。
三、常见指令
  1. echo $[变量名]:显示某个环境变量值。
  2. 在文件中修改环境变量:
    ①vim ~/.bash_profile
    ②source [修改过的环境变量文件] :在文件中修改的设置时永久生效的,需要重新加载已修改过的环境变量;
  3. 在命令行中修改环境变量只在当前bash下有用:
    ①export [环境变量名] = 环境变量值
    ②export [环境变量名] = $[环境变量名] : [新增的环境变量]。
  4. env:显示所有环境变量及其值。
    当前用户的环境变量:~/.bashrc ~/.bash_profile
  5. set:显示本地定义的shell变量和环境变量。
    系统下的环境变量:/etc/bashrc
  6. readonly:将环境变量设为只读状态。
  7. unset [环境变量名]:清除环境变量。
四、组织方式

在这里插入图片描述
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串

五、通过代码获取环境变量
  1. 命令行参数
#include <stdio.h>
int main(int argc, char* argv[], char* env[])  //argc为命令行参数的个数
{
	int i = 0;
	for (; i < argc; i++)
		printf("argv[%d] = [%s]\n", i, argv[i]);
	for (i = 0; env[i]; i++)
		printf("env[%d] = [%s]\n", i, env[i]);
	return 0;
}
  1. 第三方变量environ获取
#include <stdio.h>
#include <unistd.h>
int main()
{
	extern char** environ;  //libc中定义的全局变量environ指向环境变量表,需要extern声明
	printf("environ[0] = [%s], pid = [%d], ppid = [%d]\n", environ[0], getpid(), getppid());
	for (int i = 0; environ[i]; i++)
		printf("environ[%d] = [%s]\n", i, environ[i]);
	return 0;
}
  1. 系统调用
#include <stdio.h>
#include <stdlib.h>
int main()
{
	char* path = getenv("PATH");  //用getenc函数来访问特定的环境变量
	printf("path = [%s]\n", path);
	return 0;
}
六、环境变量通常具有全局属性,可以被子进程继承
[dev@localhost c]$ vim test.c
#include<stdio.h>
#include<stdlib.h>
int main()
{
    char * env = getenv("MYENV");
    if(env)
      printf("%s\n",env);
    return 0;
}
[dev@localhost c]$ gcc test.c -o test
[dev@localhost c]$ ./test  //没有结果,证明环境变量不存在
[dev@localhost c]$ export MYENV="helloworld"  //导出环境变量
[dev@localhost c]$ ./test
helloworld  //导出环境变量后才显示
#include <stdio.h>  //MyGetenv
int main(int argc, char* argv[])
{
    int i = 0;
    for(i = 0; i < argc; i++)
        printf("argv[%d]:%s\n", i, argv[i]);
    extern char** environ;
    for(i = 0; environ[i]; i++)
        printf("environ[%d]:%s\n", i, environ[i]);
    return 0;
}

程序地址空间

一、进程虚拟地址空间
#include <stdio.h>
#include<stdlib.h>
#include <unistd.h>
int g_Val = 10;
int main()
{
	pid_t ret = fork();
	if (ret < 0)
		return ret;
	if (ret > 0) {
		sleep(2);
		printf("father [%d]-[%d]- g_Val = [%d][%p]\n", getpid(), getppid(), g_Val, &g_Val);
	}
	else {
		g_Val = 100;
		printf("child [%d]-[%d]- g_Val = [%d][%p]\n", getpid(), getppid(), g_Val, &g_Val);
	}                       
	return 0;
}
child [10574]-[10573]- g_Val = [100][0x601054]  //变量值不一样,但地址一样
father [10573]-[4723]- g_Val = [10][0x601054]

释:
①父子进程输出的变量不是同一个变量,但地址是一样的,说明该地址绝不是物理地址。
②在Linux地址下,这种地址叫做虚拟地址,它是人为规定的,不能存储数据;我们在用C/C++语言所看到的地址,都是虚拟地址。
③存储数据依靠介质。即物理内存,而物理地址,用户一概看不到,由OS统一管理,OS必须负责将虚拟地址转化成物理地址。

  1. 页表: 映射进程虚拟地址空间。
    写实拷贝: 数据发生修改,才分配一个物理内存,并且会改变页表当中的映射关系。 eg. 上述代码中,若g_val的变量值不修改为100,那么子进程的页表映射关系不变,仍然指向物理内存中的g_val=10。
    在这里插入图片描述
二、存储器管理方式
  1. 分页式: 将虚拟地址分成一页一页的格式,将物理内存分成一块一块的格式。(块大小一般为4096KB)
    在这里插入图片描述
    页号 = 虚拟地址 / 块大小;
    页内偏移 = 虚拟地址 % 块大小;
    块号:根据页号在页表中的映射查找块号;
    块的起始地址 = 块号 * 块大小;
    物理地址 = 块的起始地址 + 页内偏移。
  2. 分段式: 将虚拟地址映射为物理地址的结构为段表,以段为单位划分,各个段的长度因程序而异。
    在这里插入图片描述
    物理地址 = 段起始地址 + 段内偏移
  3. 段页式:
    在这里插入图片描述
    页的起始地址:根据段号在段表中的映射查找页的起始地址;
    页内偏移 = 虚拟地址 % 块大小;;
    块号:根据页号在页表当中的映射查找块号;
    块的起始地址 = 块号 * 块大小;
    物理地址 = 块的起始地址 + 页内偏移。

注:
分页式存储数据效率高,分段式效率低;
分段式可通过段表的结构,找到虚拟地址空间当中的一段。

三、进程优先级
  1. 是为了保证操作系统调度进程时比较合理,可以使用 top 命令查看。
  2. PR为进程优先级的数值,数值越小代表优先级越高,用户不能直接修改该值来改变进程优先级。
  3. NI为进程优先级的修正值,用户可以改变该值来影响进程优先级,PR(new)=PR(old)+NI,
    top -> r -> PID -> 输入NI值 (范围:-20~19),
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值