环境变量
需要执行一个程序(指令)时,首先要找到这个程序,也就是为什么运行可执行文件是需要./XXX,这就是通过路径找到程序(. 代表当前目录)。可以通过将程序拷贝到系统默认的搜索路径上(/usr/bin/),例如 ls,pwd 这些指令就是在系统默认的搜索路径里,所以使用的时候就不需要带上路径系统会自动的找到这些指令的路径。
Linux命令行是可以定义变量的,而环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。如果自己定义了一个变量,这个变量并不属于环境变量而是本地变量,环境变量是具有全局性的,而自定义变量是局部的。可以通过export指定将本地变量改变为环境变量
常用的环境变量指令与调用
echo:
显示某个环境变量值
export:
设置一个新的环境变量。
env:
显示所有环境变量
unset:
清除指定环境变量
getenv():
获取指定的环境变量
environ 这是一个二级指针里面的元素就是全部系统环境变量
extern char** environ
main函数的参数
main函数的参数:
main函数实际上是可以有三个参数的
第一个参数:argc是个整型变量,表示命令行参数的个数(含第一个参数)。
第二个参数:argv是个字符指针的数组,每一个元素一个字符指针,指向一个字符串。这些字符串就是命令行中的每一个参数(字符串)
第三个参数:env是字符指针的数组,数组的每一个原元素是一个指向一个环境变量(字符串)的字符指针、
当向命令行输入指令时,命令行解释器会获取到指令信息,以空格为分隔符依次输入到argv数组中,并根据数组每个元素的不同可以指定不同的操作。
进程地址空间
先来看一个现象:
如果在同一个程序里让父子进程同时读取一个变量,它们读到地址是一样的,但是它们对变量进行修改却不会影响其他进程的读取结果。
根据这个现象就可以知道进程所指向的地址不可能是常规的物理地址。
事实上进程所指向的地址是一个虚拟地址,每个进程都对应着一个虚拟地址空间(进程地址空间),也就是其独有的且虚拟的地址,而这个地址不会影响现实中的物理空间
根据进程独立性的性质,可以知道子进程和父进程是两个相互独立的进程,也就是说它们之间做的任何事情都是互不干扰的。因为子进程是父进程创建出来的,所以子进程的地址空间是由父进程拷贝出来的,因此在子进程还未改变变量值之前看到的是同样的地址和同样的值。
也就是说,父子两进程一开始通过页表映射到物理地址时所指向的是同一块的空间。随后当子进程去修改空间的值时,操作系统为了确保进程之间的独立性,会自动进行写时拷贝,重新开辟一块空间并把子进程修改后的变量值写入到该空间,随后子进程通过页表映射到物理地址中指向的就不再是原来的空间了,而是新开辟的这块空间。因此为什么看到的是两个进程打印出来的值不一样。因为程序中打印地址打印的是虚拟地址空间,所以看到两个进程打印出来的地址是一样的。
发生改变前:
发生改变后:
写时拷贝:
在数据第一次写入到某个存储位置时,首先将原有内容拷贝出来,写到另一位置处,然后再将数据写入到存储设备中,该技术只拷贝在拷贝初始化开始之后修改过的数据。操作系统自动执行
虚拟地址的作用
为了保护物理内存
如果让进程直接的去访问物理内存,那假如进程干一些“非法”的操作,例如越界访问等,那物理内存就直接崩溃了。就跟shell命令外壳一样都是为了起到保护作用
更方便进行进程和进程数据的解耦
因为进程时具有独立性的,有了进程地址空间后,进程之间的数据就不会互相干扰确保了进程的独立性
统一视角
进程地址空间可以让进程以统一的视角去看待进程对应的代码和数据等各个区域,同时也方便使用的编译器也已统一的视角进行编译
操作系统的管理
操作系统的本身会存在着大量的进程,为了管理这些进程,操作系统会使用内核数据结构去对每一个进程管理。进程的地址空间实际上是操作系统内核的一种mm_struct的数据结构,操作系统会为每一个进程创建一个mm_struct对象。
end - start就是这块区域的大小,所以例如利用new开辟一块在堆上的空间,其实就是在调整堆区域对应的end值