冯诺依曼体系
- 我们平时使用的计算机,服务器大部分都遵守冯诺依曼体系
- 而我们平时所认识的计算机,都是由一个个硬件组成的:输入单元,输出单元,中央处理器(cpu)
- CPU能并且只能对内存(存储器)进行读写,不能访问外设(即输入和输出设备)
- 外设如果需要输入或者输出数据,只能写入内存之后在进行读写
- 所以,总而言之,所有的设备若想进行读写等操作,必须要在内存中处理。
- 例:在我们进行QQ发送消息时,消息先是经过 应用层等到达内存,然后进行数据的改变,称为二进制数,进行传输。
操作系统
- 操作系统是计算机中的基本的程序整合
- 操作系统包括内核和其他程序
内核又包括进程管理,内存管理,文件管理和驱动管理
其他程序包括:函数库,shell程序等等
在管理硬件时:描述用struct,组织用链表等数据结构操作
操作系统对外是一个整体,但是会暴露自己及的一些接口供系统调用,这样用户在调用的时候为了方便会进行适当的封装,形成了库。
进程
- 概念:进程是程序的一个执行实例,正在执行的程序。
- 描述进程信息放在一个叫做进程控制块的数据结构中,叫做PCB,linux下的PCB的结构体是task_struct(linux内核中的一种数据结构)
- 这个结构体中包含:
- 标识符:描述进程的唯一表示方法,用来区别于不同的进程
- 状态:任务状态,退出代码,退出信号等
- 内存指针:程序代码和进程数据相关的指针,还有和其他进程共享的内存块指针
- ……还有许多的内容,例如信号,优先级等
- 如何查看进程的基本信息:
[@localhost day01]$ ls /proc/
1 10798 1573 1819 1979 2214 2266 2325 2875 7
10 10908 1598 1899 2 2219 2271 2326 2883 71
10167 11 16 19 20 2221 2272 2328 29 788
10170 12 1668 1907 2049 2226 2276 2347 3 8
..........
父进程和子进程
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
printf("pid:%d\n",getpid());//进程ID
printf("ppid:%d\n",getppid());//父进程id
}
执行结果
[root@localhost day01]# ./a.out
pid:10956
ppid:10942
- 用fork创建一个子进程:若小于0,说明进程没有创建成功;若等于0,说明子进程创建成功,并给父进程返回自己的id值。
进程的状态
- 进程的状态分为:运行,睡眠,磁盘休眠,停止,死亡,僵尸6个状态。
- 其中较为常见的是运行和停止状态。
较为特殊的是僵尸状态:在进程退出后并且父进程调用了wait()函数等待子进程但是没有获取到子进程返回退出码时,这时候就会进入僵尸状态。
孤儿进程
- 产生的原因:父进程提前退出,子进程后退出,进入了僵尸状态;这时候子进程就变成了孤儿进程,孤儿进程被1号init领养,最后进入init 回收。
进程优先级
- 基本概念:CPU (中央处理器)对内存进行资源分配时,会有先后和高低顺序,这种指的就是进程优先级
- 还可以将进程分配到指定的CPU下,这样方便管理,提高性能。
- 在linux下PRI 表示进程的优先级,值越小,说明优先级越高;而nice值是可以调整PRI 的一种存在。
[root@localhost day01]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 10933 10652 0 80 0 - 2254 - pts/2 00:00:00 su
4 S 0 10942 10933 0 80 0 - 1282 - pts/2 00:00:00 bash
[root@localhost day01]# renice -5 -p 10933//将进程id为10933的nice改为-5
10933: old priority 0, new priority -5
[root@localhost day01]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 10933 10652 0 75 -5 - 2254 - pts/2 00:00:00 su
4 S 0 10942 10933 0 80 0 - 1282 - pts/2 00:00:00 bash
4 R 0 11042 10942 0 80 0 - 1219 - pts/2 00:00:00 ps
环境变量
- 环境变量一般是指在操作系统中用来指定操作系统运行环境的参数
- 例如在c/c++中,程序在链接的时候往往是通过环境变量来寻找链接所需要的动态静态库。
- echo :显示某个环境变量的值
- export:设置一个新的环境变量
- env:显示所有的环境变量
- unset:清除环境变量
- set:显示本地定义的shell变量和环境变量
- 访问特定的环境变量:getenv,putenv
- 环境变量可以被子进程继承下去
[root@localhost day02]# gcc 2.c
[root@localhost day02]# ./a.out
haha
[root@localhost day02]# echo $HOME//用root身份执行
/root
[henina@localhost day02]$ echo $HOME//用普通用户身份执行
/home/henina
程序地址空间
- 父进程和子进程若没有发生太大的改动,环境变量以及地址都是一样的,因为子进程是依照父进程为模板的。
- 但是在执行子进程的时候将环境变量改变,最终得出的地址还是一样的
- 所以,由此可得出:地址是虚拟地址,我们在c/c++语言中所看到的地址都是虚拟地址,物理地址一般看不到,由OS管理。而OS也有义务将虚拟地址转换为物理地址
进程地址空间
- 早期的进程地址空间不隔离,所以会有恶意的程序对其他的进程进行修改
- 内存的使用效率低:在两个文件都在运行的情况下,第三个程序若是需要运行,但是内存不够用,这时候就需要从正在运行的程序中选择一个将第三个程序的所需要的数据拷贝到硬盘上,释放空间供第三个程序使用,然后将三个程序的数据全部装入内存中运行。
- 程序运行的地址不确定:程序开始都是物理地址,但是物理地址需要加载后才能确定。而在程序开始运行时,满足了运行条件之后,内存随即分配地址,所以地址不确定。
分段
- 在编写代码的时候,代码段和数据段出现的所有的地址,都是从0开始的。
CPU将内存分割成了不同的段,所以指令和数据的有效地址都不是真正的物理地址,而是相对于段首位置的偏移地址。
-分段解决了进程地址空间的不隔离的问题,也解决了程序运行地址不确定的问题(指令地址都是从0开始,系统进行自动化映射物理地址)但是没有解决性能问题
分页/虚拟地址空间
- 由图可以看出,同一个变量,地址相同,其实是虚拟地址相同,内容不同是因为被映射到了不同的物理地址。