本文重点:
1.环境变量;
2.程序地址空间;
3.进程优先级;
一.环境变量:
环境变量:指在操作系统中用来指定操作系统中的运行环境的一些参数;
1.常见的环境变量:
PWD:当前系统的工作路径;
LANG:当前系统的工作语言;
HOME:当前的家目录下;
PATH:以冒号间隔的路径;
SHELL:命令行解释器;
(PATH环境变量是一个重点;它的作用是指定一个可执行程序的默认搜索路径)
2.查看环境变量:env ; set ; echo;
(1)用env进行查看:
在env查看时,我们可以看到所有的环境变量,以及每个环境变量下的内容;
(2)set可以查看环境变量以及所有常量;
(3)echo查看环境变量;(指定查看某个环境变量下的内容)
echo $+环境变量名
3.设置环境变量:export
4.删除环境变量:unset grep | 变量名
5.环境变量的继承特性:
通过程序来演示一个环境变量的获取演示:
//第一种方法:通过环境变量名来获取内容:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
//接口:char * getenv(const char* name);通过环境变量来获取变量内容;
char * ptr=getenv("PWD");
printf("ptr: %s\n",ptr);
return 0;
}
执行结果:
//第二种方法:获取所有环境变量;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char * argv[],char* env[]){
int i;
for(i=1;env[i]!=NULL;i++){
printf("env[%d]=[%s]\n",i,env[i]);
}
return 0;
}
程序执行结果:
//第三种获取方法:获取所有环境变量----extern关键字;
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char * argv[],char* env[]){
int i;
extern char** environ;
//标准库中environ是一个全局变量,该全局变量就是一个局部变量;
//extern 是一个声明,声明environ是一个环境变量;
for(;environ[i]!=NULL;++i){
printf("env[%d]=[%s]\n",i,environ[i]);
}
return 0;
}
程序执行结果为:
总结:环境变量的特性(继承特性):
1.shell终端下所运行的进程能够获取所有的环境变量,但是获取不到普通变量;
2.在程序中获取环境变量:char * getenv(char*name)
3.声明全局变量:extern关键字-----》extern char** environ;
6.环境变量的全局特性:在子进程中获取继承于父进程的环境变量信息;
main(int argc,char * argv[],char *env[]) 参数获取
extern char **environ; 全局变量获取
char * getenv(const char *env_name) 接口获取
二.程序地址空间:(非常重要)
以上是一个内存空间示意图,也是一个程序地址空间的示意图-------虚拟内存空间;
1.什么是内存地址??
内存地址就是内存中的一个编号;
2.什么是程序地址空间??
程序地址空间即虚拟地址空间;
我们通过这段代码来进行验证:
#include <unistd.h>
#include <stdio.h>
int g_val=100; //设置一个全局变量g_val为100;
int main(){
printf("hello world ------pid:%d\n,getpid());
pid_t pid=fork(); //创建一个进程;
if(pid<0){
printf("fork error\n");
}
else if(pid==0){
g_val=200; //当为子进程时输出200;
printf("----i am child-----%d g_val:%d-----%p\n,getpid(),g_val,&g_val);
}
else{
sleep(1);
printf("----i am parent----%d g_val:%d-----%p\n,getpid(),g_val,&g_val);
}
printf("nihao~~ pid:%d\n",getpid());
while(1)
sleep(1);
}
return 0;
}
程序的输出结果为:
我们发现父子进程拥有相同的地址,但输出的值不一样;因此肯定用的不是一块相同的内存区域;
为什么不同的内存区域会有相同的地址呢??----这块内存区域不是一块物理内存地址;而是一块虚拟地址;
我们申请一块变量,给他分配一块内存地址,实际上是给他分配了一块虚拟内存地址;
3.虚拟内存地址空间该如何存储数据??
程序地址空间是一个虚拟地址空间 mm_struct的结构体;(内存描述符,该结构体描述了一个虚拟地址空间)
mm_struct
{
long int size (size 描述了当前的地址空间有多大)
//描述各个区域;
long int code_start (描述代码段的起始位置信息)
long int code_end
long int data_start (描述数据段的起始位置信息)
long int data_end
}
......
4.为什么需要使用虚拟地址空间??
每个程序都需要一块连续的内存地址空间;进程在通过访问虚拟地址进而获得变量数据,最终还是要去访问物理内存的,因为数据是存储在物理内存中的;
在虚拟地址和物理地址之间通过页表进行地址映射,转换得到物理地址,进而访问物理内存区域;通过映射之后的物理地址不一定连续,通过映射转换的方式,实现数据的离散存储,提高内存的利用率;
原理如下图所示:
5.写时拷贝技术:
父进程有一个虚拟地址空间,然后父进程fork()了一下创建了一个子进程,该子进程父进程完全一样;他们指向的位置是完全相同的,但当这块内存区域的数据发生改变的时候,为了互不影响,因此为子进程重新开辟了一个内存空间,更新页表的映射关系;-------------数据独有,代码共享
写时拷贝技术的优点:
(1)节省资源;
(2)提高子进程创建效率;
6.虚拟地址空间的作用:
(1)提高内存利用率;
(2)增加内存访问控制;
(3)保持进程独立性;
7.页表的功能:
(1)记录虚拟地址和物理地址之间的映射关系;
(2)并且对虚拟地址进行内存访问控制;
8.页表是如何将虚拟内存转换为物理内存地址的????
(1)分段式内存管理:
内存地址的构成:段起始地址(段号)+段内偏移;
段表:在操作系统中做了记录—这块内存分了多少段;
在段表中有很多的段表项,每一项都有一个段的起始地址(物理段的起始地址);通过段号找到物理段的起始地址,然后加上段内偏移就是段的物理地址;
总结:通过地址中的段号去段表找到段表项,通过段表项中的物理起始地址加上地址中的段内偏移获取物理地址;
(2)分页式内存管理:
内存地址的构成:页号+页内偏移;
内核中----页表(有很多页表项)—32位操作系统下有2^20个页表项;
页号在虚拟页号中找,然后找到对应的物理页号;物理页号+页内偏移----》内存中的物理地址;
总结:通过地址中的页号去页表中找到页表项,通过页表项中的物理页号加上页内偏移进而获取到物理地址;
在我们当前的虚拟地址空间中采用的是段页式内存管理:
我们的内存是通过分段式进行管理的,因为分段式更加易于编程;而在段内使用的是分页式;首先通过取地址得到段号,在段表中进行查找;在段表中有一个段内页表起始地址,找到段内页表起始地址就可以找到页表了;
段页式内存管理:内存地址:段号+段内页号+页内偏移;
段表项中有段内页表起始地址;段内页表项中又包含物理页号;
总结:通过段号在段表中找到段表项,通过段表项中的段内页表地址找到段内页表,通过地址中的段内页号在段内页表中找到页表项,通过页表项中的物理页号与页内偏移组成物理地址;
9.内置换算法:
实例:当一个操作系统的内存只有4G,但是要处理5G的数据,怎么办???
swap分区也叫交换内存:内存不够时,将内存中的数据置换到交换分区中,腾出内存处理数据;
如何来进行置换:三种方法
(1)FIFO:先进先出,核心原则:如果一个数据最先进入缓存中,则应该最早被淘汰;
(2)LFU:最近最少使用算法;基于访问次数;
(3)LRU:最近最久未使用算法;
三.进程优先级概念:
1.优先级的概念:
优先级就是决定资源优先分配权的等级划分;
2.设定进程优先级的好处:
(1)配置进程优先权对多任务环境的linux可以改善系统性能;
(2)可以把进程运行到指定的CPU上,把不重要的进程安排到某个CPU,可以大大改善系统整体性能;
因为在操作系统上多个进程完成的工作都不一样,为了使CPU处理数据更具有效率性,所以划分产生交互式进程和批处理进程;
3.关于进程优先级的几个重要信息:
我们通过进程查看可看到在第一行有一些信息:
UID : 代表执行者的身份;
PID : 代表这个进程的代号;
PPID :代表这个进程是由哪个进程发展衍生而来的,即父进程的代号;
PRI :代表这个进程可被执行的优先级,其值越小越早被执行;
NI :代表这个进程的nice值;
4.如何修改进程的优先级:
在Linux下调整进程的nice值就是调整进程的优先级;
PRI (优先级是一个数字,无法直接设置,可设置NI值,进而进行调整PRI);
NI (nice值,PRI无法直接设置,但可通过设置NI值,进而调整)
优先级的修改:PRI=PRI+NI;
5.关于优先级的几个概念:
并行:CPU资源足够多,多个进程可同时工作;
并发:CPU资源不够多,多个程序切换运行,同时推进;
独立性:进程间相互独立;
竞争性:系统进程数目众多,但CPU只有一个,所以进程之间就具有了竞争属性。为了高效完成任务,更合理竞争相关资源,便具有了优先级;