当前位置: 首页 > news >正文

Linux--进程地址空间

 

目录

4. 环境变量

4-1 基本概念

4-2 常⻅环境变量

4-3 查看环境变量⽅法

4-4 和环境变量相关的命令

4-5 环境变量的组织⽅式

4-6 通过代码如何获取环境变量

4-7 环境变量通常是具有全局属性的

5. 程序地址空间

5-1 研究平台

5-2 程序地址空间回顾

5-3 虚拟地址

5-4 进程地址空间

5-5 虚拟内存管理 - 第⼀讲


4. 环境变量

4-1 基本概念

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

4-2 常⻅环境变量

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

4-3 查看环境变量⽅法

echo $NAME //NAME:你的环境变量名称
测试PATH
1. 创建hello.c⽂件
#include <stdio.h>
int main()
{
printf("hello world!\n");
return 0;
}
2. 对⽐./hello执⾏和之间hello执⾏
3. 为什么有些指令可以直接执⾏,不需要带路径,⽽我们的⼆进制程序需要带路径才能执⾏?
4. 将我们的程序所在路径加⼊环境变量PATH当中, export PATH=$PATH:hello程序所在路径
5. 对⽐测试
6. 还有什么⽅法可以不⽤带路径,直接就可以运⾏呢?
测试HOME
1. ⽤root和普通⽤⼾,分别执⾏ echo $HOME ,对⽐差异
2. 执⾏ cd ~; pwd ,对应 ~ HOME 的关系

4-4 和环境变量相关的命令

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

4-5 环境变量的组织⽅式

每个程序都会收到⼀张环境表,环境表是⼀个字符指针数组,每个指针指向⼀个以’\0’结尾的环境
字符串

4-6 通过代码如何获取环境变量

命令⾏第三个参数
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
for(; env[i]; i++){
printf("%s\n", env[i]);
}
return 0;
}
通过第三⽅变量environ获取
#include <stdio.h>
int main(int argc, char *argv[])
{
extern char **environ;
int i = 0;
for(; environ[i]; i++){
printf("%s\n", environ[i]);
}
return 0;
}
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头⽂件中,所以在使⽤时 要⽤
extern声明。

4-7 环境变量通常是具有全局属性的

环境变量通常具有全局属性,可以被⼦进程继承下去

5. 程序地址空间

5-1 研究平台
kernel 2.6.32
32位平台
5-2 程序地址空间回顾
我们在讲C语⾔的时候,⽼师给⼤家画过这样的空间布局图

可是我们对他并不理解!可以先对其进行各区域分布验证

5-3 虚拟地址
来段代码感受⼀下
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
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;
}
输出
//与环境相关,观察现象即可
parent[ 2995 ]: 0 : 0x80497d8
child[ 2996 ]: 0 : 0x80497d8
我们发现,输出出来的变量值和地址是⼀模⼀样的,很好理解呀,因为⼦进程按照⽗进程为模版,⽗
⼦并没有对变量进⾏进⾏任何修改。可是将代码稍加改动

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
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;
}
输出结果:
//与环境相关,观察现象即可
child[ 3046 ]: 100 : 0x80497e8
parent[ 3045 ]: 0 : 0x80497e8

我们

变量内容不⼀样,所以⽗⼦进程输出的变量绝对不是同⼀个变量
但地址值是⼀样的,说明,该地址绝对不是物理地址!
在Linux地址下,这种地址叫做 虚拟地址
我们在⽤C/C++语⾔所看到的地址,全部都是虚拟地址!物理地址,⽤⼾⼀概看不到,由OS统⼀
管理
OS必须负责将 虚拟地址 转化成 物理地址 。
5-4 进程地址空间
所以之前说‘程序的地址空间’是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?看
图:
分⻚&虚拟地址空间

发现,⽗⼦进程,输出地址是⼀致的,但是变量内容不⼀样!能得出如下结论: 

说明:
上⾯的图就⾜矣说明问题,同⼀个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映
射到了不同的物理地址!

5-5 虚拟内存管理 - 第⼀讲
描述linux下进程的地址空间的所有的信息的结构体是 mm_struct (内存描述符)。每个进程只有⼀
个mm_struct结构,在每个进程的task_struct结构中,有⼀个指向该进程的结构。
可以说,mm_struct结构是对整个⽤⼾空间的描述。每⼀个进程都会有⾃⼰独⽴的mm_struct,这样
每⼀个进程都会有⾃⼰独⽴的地址空间才能互不⼲扰。
5-6 为什么要有虚拟地址空间
这个问题其实可以转化为:如果程序直接可以操作物理内存会造成什么问题?
在早期的计算机中,要运⾏⼀个程序,会把这些程序全都装⼊内存,程序都是直接运⾏在内存上的,
也就是说程序中访问的内存地址都是实际的物理内存地址。当计算机同时运⾏多个程序时,必须保证
这些程序⽤到的内存总量要⼩于计算机实际物理内存的⼤⼩。
那当程序同时运⾏多个程序时,操作系统是如何为这些程序分配内存的呢?例如某台计算机总的内存
⼤⼩是128M,现在同时运⾏两个程序A和B,A需占⽤内存10M,B需占⽤内存110。计算机在给程序分
配内存时会采取这样的⽅法:先将内存中的前10M分配给程序A,接着再从内存中剩余的118M中划分
出110M分配给程序B。
这种分配⽅法可以保证程序A和程序B都能运⾏,但是这种简单的内存分配策略问题很多。
安全⻛险
每个进程都可以访问任意的内存空间,这也就意味着任意⼀个进程都能够去读写系统相关内
存区域,如果是⼀个⽊⻢病毒,那么他就能随意的修改内存空间,让设备直接瘫痪。
地址不确定
众所周知,编译完成后的程序是存放在硬盘上的,当运⾏的时候,需要将程序搬到内存当中
去运⾏,如果直接使⽤物理地址的话,我们⽆法确定内存现在使⽤到哪⾥了,也就是说拷⻉
的实际内存地址每⼀次运⾏都是不确定的,⽐如:第⼀次执⾏a.out时候,内存当中⼀个进程
都没有运⾏,所以搬移到内存地址是0x00000000,但是第⼆次的时候,内存已经有10个进程
在运⾏了,那执⾏a.out的时候,内存地址就不⼀定了
效率低下
如果直接使⽤物理内存的话,⼀个进程就是作为⼀个整体(内存块)操作的,如果出现物理
内存不够⽤的时候,我们⼀般的办法是将不常⽤的进程拷⻉到磁盘的交换分区中,好腾出内
存,但是如果是物理地址的话,就需要将整个进程⼀起拷⾛,这样,在内存和磁盘之间拷⻉
时间太⻓,效率较低。
存在这么多问题,有了虚拟地址空间和分⻚机制就能解决了吗?当然!
http://www.dtcms.com/a/99108.html

相关文章:

  • Java基础关键_032_反射(二)
  • 六十天前端强化训练之第三十四天之CI/CD 大师级深度解析
  • CNN+Transformer+SE注意力机制多分类模型 + SHAP特征重要性分析,pytorch框架
  • NFS挂载异常排查记录
  • 比kubectl更好用的k8s命令行客户端kube-shell
  • 信号集操作函数
  • Object结构
  • sqli-labs靶场 less 8
  • Display Serializer、Camera Deserializer(Camera Des)和SerDes‌ 加解串应用
  • 【vllm/瞎折腾】在内网wsl上安装vllm并尝试多节点部署(失败了)
  • Java并发编程面试题:线程池Fork/Join(19题)
  • 【深度学习新浪潮】具身智能及其发展前景分析
  • 万物皆可“吉卜力”,使用 AI 创建你的作品
  • 逆向中如何判断JSVMP,及如何解决?(包括实战案例)
  • OpenAI API - Agent
  • protobuf新版下载安装
  • 网络通信微服务
  • 【商城实战(95)】Ansible自动化运维,开启高效部署新篇章
  • 3D Gaussian Splatting部分原理介绍和CUDA代码解读(一)——3D/2D协方差和高斯颜色的计算
  • LeetCode 56. 合并区间 | 排序+贪心解法详解
  • 创意 Python 爱心代码分享
  • el-table 动态给每行增加class属性
  • C++ vector容器总结
  • 诠视科技MR眼镜如何使用VLC 进行RTSP投屏到电脑
  • 【从零实现Json-Rpc框架】- 项目实现 - muduo网络通信类实现篇
  • 黑盒测试的测试用例构成的八点要素
  • 突破数据迁移瓶颈!AWS Snowball如何让PB级数据“瞬间”上云?
  • 12款星光闪光污迹艺术绘画效果Clip Studio Paint笔刷画笔+闪光纹理图片 Clip Studio Glitter Texture Brushes
  • INAV电流计校准
  • sqlalchemy:将mysql切换到OpenGauss