Linux进程概念(三)
环境变量与进程地址空间
- 环境变量
- 什么是环境变量
- 常见环境变量
- 环境变量相关命令
- 环境变量的全局属性
- PWD
- main函数的三个参数
- 进程地址空间
- 什么是进程地址空间
- 进程地址空间,页表,内存的关系
- 为什么存在进程地址空间
环境变量
什么是环境变量
我们所有写的程序都需要指定路径才能运行,就像这样:(程序里面是打印DLC循环)
生成的etv是一个可执行程序,但是我们平时使用的指令比如 ls 等等也都是可执行程序,但是并不需要指定目录在哪里才可以使用。
如果将刚才写的etv程序拷贝到/usr/bin 会不会与ls一样可以直接使用?
这样是可以的,但是非常不建议,因为这个程序相当于安装到了系统中,Linux下拷贝就是安装。
那么系统是如何找到的,是因为有一个环境变量——PATH,他在全局都是有效的,是系统默认的指令搜索路径(想查看前面加$):
这是查看PATH环境变量中的内容,用 : 隔开的是不同路径。
添加路径:
只不过这样也就等于把原来的路径覆盖了,只剩下的/home/mfc这个目录了,也就等于在想执行 sl 这种就需要取指定目录才可以。
不过不用担心,重新登陆Linux就可以了,因为这是内存上的改变。
那么我们需要保留原来的并且再添加新的:
这样也不会影响原来的sl等。
在打开Linux的时候bash因为要处理用户的命令,这些命令也是程序,运行程序需要指定路径,所以操作系统就提前将这些指令的路径放在了专属的配置文件,在启动操作系统时将这个文件导入内存中形成一个内存级变量,这就是环境变量。
那么最开始的环境变量是怎么来的呢?
这两个文件里面内容是脚本,内容就是将环境变量导入当前的shell中(这个环境变量是内存级的)。
常见环境变量
HOME 当前用户的工作目录
HOSTNAME 当前主机名
LOGNAME 当前用户名
HISTSIZE 显示储存多少命令内容(历史输入的命令,有一个命令可以查看历史输入的命令,history)
环境变量相关命令
echo: 显示某个环境变量值(记得加$)
export: 设置一个新的环境变量
env: 显示所有环境变量
unset: 清除环境变量
set: 显示本地定义的shell变量和环境变量
环境变量的全局属性
我们也可以定义本地变量:
但是本地变量是无法被子进程继承,我们用一段代码来验证:
参数是定义的变量,如果有这个环境变量就返回一个数值,没有就返回空指针。
这是因为我们刚才定义的变量是在bash上的,bash是一个系统进程,我们的etv是一个可执行文件,运行起来也是一个进程,就是bash的子进程,刚才定义的变量也叫本地变量,不具有全局属性,所以没有传到etv进程里面,就像C语言当中的全局变量和局部变量一样。
这里将本地变量变成环境变量。
环境变量是具有全局属性的,会被子进程继承下去。
PWD
执行可执行程序在当前路径是需要带路径的,但是ls并不需要,这是为什么呢?
因为有一个环境变量PWD是当前路径:
上面我们知道了环境变量会被子进程继承,ls是bash的子进程,所以继承了这个环境变量,就知道了当前路径,所以可以这样执行命令:
main函数的三个参数
在调用某个程序的时候是调用main函数然后才开始运行,那么我们在调用某个程序的时候会带选项,其实这些选项就是前两个参数,第三个参数就是环境变量的参数。
argc是代表有多少个选项,argv[]是一个指针数组,里面是char*,储存的就是程序名与选项,env[]是储存环境变量的指针数组。
先来看看argv与argv[]:
对着这段命令行解析是这样的:
这个过程是由shell和系统来完成的。
这时就平时带选项程序是如何完成各个功能的原因。
然后来看看第三个参数:
这里就是环境变量了。
当然获取环境变量还有一种方法,C语言提供了一个第三方的变量:
这个是全局环境变量的指针,也就是指向env[]那个表,这样main函数不用传参也可以获取环境变量。
使用之前必须声明一下自己要用environ变量。
进程地址空间
之前有过一张在C/C++语言层面上的地址空间图:
磁盘上面写的程序都是需要先加载到内存里才能运行的,那么这张图是物理方面的内存嘛?并不是,来看这段代码:
每个进程都是有独立性的,按理来说应该是都有单独的空间,可是在两个进程运行中,全局变量a的地址竟然是一样的,这难道说明a是被两个进程公用的吗?但是a在子进程当中又被改掉了,可是父进程当中的却没有改变,地址也完全相同。
这是因为当前显示a的地址是虚拟地址。
我们之前在用VS编译器调试的时候看到的地址都是虚拟地址,物理地址普通用户看不到,这些都由操作系统来管理。
什么是进程地址空间
下面我用32位机器举例子。
那么既然地址空间是虚拟空间,到底有什么用处,到底是怎么实现的呢?
虚拟空间是操作系统防止用户把物理内存给玩坏所弄出来的空间,是通过页表来进行映射和管理的:
在32位的机器中,操作系统会给每个进程“画个大饼”,说你们每个进程都可以分配到2^32字节(约等于4GB)的空间大小,并且每个地址都是独立不冲突的。
普通进程当然不可能一下子全都使用掉,所以理论上来说每个进程都可以有4GB的空间,但是如果某个进程需要的不是特别多或者是需要的特别多,这个时候操作系统就会调整大小了。
首先来看看进程地址空间是什么原理:
在linux源码当中,地址空间是一个mm_struct的数据结构,大概是这样的
struct mm_struct
{uint32_t code_start,code_end;uint32_t data_start,data_end;uint32_t heap_start,heap_end;uint32_t stack_start,stack_end;
};
不同区域分别赋值不同的地址就好了,如果有需要再去调整就好了,毕竟这是虚拟地址,怎么搞都搞不坏。
也就是说虚拟空间的本质就是控制这些数据而已。
进程地址空间,页表,内存的关系
一个程序在磁盘里,先放入内存中,然后代码跑起来,代码也是需要储存在内存上的,并且内存当中是类似于数组形式的,一个page位4kb大小。
进程在运行的时候有自己的虚拟地址空间,然后通过页表来映射到物理内存上的。
这些都是由操作系统完成的。
这也就能解释刚开始代码为什么是显示的是同一个地址,子进程改变了数值父进程却没有改变。
因为每个进程都有独立的进程地址空间和页表:
页表不单单只是映射,并且还会去判断,拦截(所有进程都不例外)像刚开始写的那段代码,因为子进程是父进程创建的,那么子进程的地址空间内容是从父进程拷贝而来的,但是页表会发现原本映射出来的位置已经被占有了,这个时候就会在另一处先开辟空间,然后拷贝父进程在内存中的内容到新开辟的空间当中,然后更改页表的映射,这个叫做写时拷贝,这样父进程和子进程就是两个完全独立的空间。
为什么存在进程地址空间
1.防止进程在物理内存当中进行越界的非法操作。(上面的例子已证明)
2.更方便进程和进程的数据代码解耦,保证了进程独立性的特征。(上面的例子已证明)
3.
遵守进程地址空间的不仅仅是操作系统还有编译器!
假设我写了一个程序my.exe。
程序在磁盘的时候是有地址的,逻辑地址(在linux当中也可以称为虚拟地址)
在进程指向进程地址空间的时候,CPU去读取指令,main函数,因为每一条指令都是有虚拟地址的,所以就能找到fun函数,还有a的位置。
CPU的寄存器中储存的就是虚拟地址,通过main函数的虚拟地址然后找到内存中的main然后解析代码,然后调用fun的时候又通过页表映射到了进程地址空间当中,CPU又拿到了fun函数的虚拟地址,然后再映射到物理内存当中,这就是我们调试代码中看到的内存地址编号就是虚拟地址空间。
上面的运行模式也说明了CPU从头到尾都没有见到过物理内存地址,就算是内存中代码的内部使用的也全都是虚拟地址。
至于逻辑地址和虚拟地址的区别,现在用的逻辑地址也是划分区域,代码区,数据区等等,恰好与虚拟地址的编号差不多,所以加载到内存当中使用的就是虚拟地址了。
旧版的逻辑地址就比较繁琐了,是靠偏移量来找到物理内存中数据的地址。
这说明进程地址空间方便了进程以统一视角来看到对应的代码,数据等各个区域,也方便编译器用同一个规则进行编译。(规则是一样的,编译完即可使用)
最后说明:
命令行参数环境变量就是那个environ。
相关文章:

Linux进程概念(三)
环境变量与进程地址空间环境变量什么是环境变量常见环境变量环境变量相关命令环境变量的全局属性PWDmain函数的三个参数进程地址空间什么是进程地址空间进程地址空间,页表,内存的关系为什么存在进程地址空间环境变量 什么是环境变量 我们所有写的程序都…...

新手福利——x64逆向基础
一、x64程序的内存和通用寄存器 随着游戏行业的发展,x32位的程序已经很难满足一些新兴游戏的需求了,因为32位内存的最大值为0xFFFFFFFF,这个值看似足够,但是当游戏对资源需求非常大,那么真正可以分配的内存就显得捉襟…...
虚幻c++中的细节之枚举类型(enum)
文章目录前言一、原生c的枚举类型关键字classint8 - 枚举的基础类型(underlying type)二、枚举类型的灵活运用位运算枚举循环遍历三、虚幻风格的枚举类型UENUMUMETATEnumAsByte总结前言 虚幻引擎中的代码部分实现了一套反射机制,为c代码带了…...
判断某个字符串在另一个字符串中的个数
/** * 用于判断字符串中字符的个数 * * param str1 原字符串 * param str2 需要判断的字符 * return 返回有几个 */ private int getCount(String str1, String str2) { //获取两个字符串的长度 int oneLength str1.length(); int toLength str2.length(); //定义两个整数&am…...

测试人员如何运用好OKR
在软件测试工作中是不是还不知道OKR是什么?又或者每次都很害怕写OKR?或者总觉得很迷茫,不知道目标是什么? OKR 与 KPI 的区别 去年公司从KPI换OKR之后,我也有一段抓瞎的过程,然后自己找了两本书看,一本是《OKR工作法》…...

CentOS7 Hive2.3.9 安装部署(mysql 8.0)
一、CentOS7安装MySQL数据库 查询载mariadb rpm -qa | grep mariadb卸载mariadb rpm -e --nodeps [查询出来的内容]安装wget为下载mysql准备 yum -y install wget在tools目录下执行以下命令,下载MySQL的repo源: wget -P /tools/ https://dev.mysql.…...
【PTA Advanced】1142 Maximal Clique(C++)
目录 题目 Input Specification: Output Specification: Sample Input: Sample Output: 思路 代码 题目 A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent. A maximal clique is a clique …...
1. MySQL在金融互联网行业的企业级安装部署
这里写目录标题 1. 版本介绍示例2.安装MySQL规范(建议二进制)2.1 安装方式2.2 安装用户2.3 目录规范3.二进制安装3.1 操作系统配置3.2 MySQL 5.7.33 安装部署2.3 MySQL8.0.27安装2.4 源码安装(了解 )3.多实例部署及注意事项3.1 多实例概念3.2 多实例安装3.3 多实例第二种方式…...

【C++修炼之路】19.AVL树
每一个不曾起舞的日子都是对生命的辜负 AVL树前言:一.AVL树的概念二.AVL树的结构2.1 AVL树节点的定义2.2 AVL树的结构2.3 AVL树的插入2.4 AVL树的验证2.5 AVL树的删除(了解)三.AVL树的旋转(重要)3.1 左单旋3.2 右单旋3.3 左右双旋3.4 右左双旋…...

项目管理工具dhtmlxGantt甘特图入门教程(十):服务器端数据集成(下)
这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表,可满足应用程序的所有需求,是完善的甘特图图表库 DhtmlxGantt正版试用下载(qun 764149912)http…...
LeetCode 793. 阶乘函数后 K 个零
f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * ... * x,且 0! 1 。 例如, f(3) 0 ,因为 3! 6 的末尾没有 0 ;而 f(11) 2 ,因为 11! 39916800 末端有 2 个 0 。 给定 k,找出返回能满足 f(x) …...

maven打包顺序与jvm类加载顺序
背景:一次dev测试过程中,发现代码中关于jsr303的校验失效,校验类如下,会报一个莫名其妙的运行时错误;遂进行排查。import javax.validation.constraints.NotBlank;Data Accessors(chain true) public class Demo {Not…...

④ 链表
24. 两两交换链表中的节点 题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/ 注意点: 遍历链表的时候什么时候截止(避免空指针异常或无限死循环的问题)? 节点数量为偶数或链表为空时,cur.ne…...

小孩扁桃体肿大3度能自愈吗?6岁小孩扁桃体肥大怎么治效果好?
12月7日,四川眉山市民唐先生说,他刚出生的儿子在妇产医院分娩中心住了20天后感染了败血症。据唐先生介绍,哈子出院时各项指标正常。他在分娩中心住了半个月左右,孩子喝牛奶很生气,第二天就开始发烧了。同一天ÿ…...

【C++提高编程】C++全栈体系(二十二)
C提高编程 第三章 STL - 常用容器 五、stack容器 1. stack 基本概念 概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口 栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为 栈中进入数据称为 — 入…...

linux系统编程2--网络编程socket知识
在linux系统编程中网络编程是使用socket(套接字),socket这个词可以表示很多概念:在TCP/IP协议中,“IP地址TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址端口号”就称为socket。在TCP协议中&#…...
Python-__repr__、__hash__和__eq__方法,split()、join()、yield()和append()函数
1.__repr__方法程序1class Python:passa Python() print(a) print(a.__repr__())结果<__main__.Python object at 0x0000023B82185FD0> <__main__.Python object at 0x0000023B82185FD0>默认情况下,我们得到的信息只会是“类名object at内存地址”程序…...

【安卓开发】安卓广播机制
读书笔记系列(第一行代码) 5.1 广播机制简介 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)有序广播:同步执行,广播发出后…...

移动WEB开发四、rem布局
零、文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789个人博客-GiteePages:https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee:https://gitee.com/bluecusliyou/TechLearnGithub:https:…...
request.getURL()和request.getURI() 以及通过request获得路径相关大全
request.getURL()和request.getURI() 如果我的请求是:http://localhost:8080/ServletTest/servlet/Hello request.getRequestURI() 返回值类似:/ServletTest/servlet/Hello request.getRequestURL() 返回值类似:http://localhost:8080/Servle…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
Java中栈的多种实现类详解
Java中栈的多种实现类详解:Stack、LinkedList与ArrayDeque全方位对比 前言一、Stack类——Java最早的栈实现1.1 Stack类简介1.2 常用方法1.3 优缺点分析 二、LinkedList类——灵活的双端链表2.1 LinkedList类简介2.2 常用方法2.3 优缺点分析 三、ArrayDeque类——高…...

vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能
vxe-table vue 表格复选框多选数据,实现快捷键 Shift 批量选择功能 查看官网:https://vxetable.cn 效果 代码 通过 checkbox-config.isShift 启用批量选中,启用后按住快捷键和鼠标批量选取 <template><div><vxe-grid v-bind"gri…...

Centos 7 服务器部署多网站
一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站,目录结构如下: bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...