1. 进程相关命令
ulimit -a : 显示进程的参数限制;比如最大打开文件个数
ulimit -n 数字: 修改文件打开个数
cat /proc/self/limits : 查看进程的一些limit,修改limit之后会导致这文件的值的变化
/proc : 伪文件系统,记录一些内核相关的信息,比如进程/cpu/文件系统等。
/self :链接到当前运行的进程,即记录当前进程的一些信息,多个进程之间不共享。
2. 进程相关概念
2.1 虚拟内存与进程
1. 每个进程都有4G的虚拟内存空间,存放栈/堆/kernel/代码等
kernel:指向相同的物理内存(多个进程共享kernel)-->内核空间(3G-4G)
栈/堆/代码:多个进程在物理内存中拥有独立的空间,不能共享-->用户空间(0G-3G):只能由当前进程访问自己的用户空间
2. 物理内存中维护一个虚拟内存映射表,维护着虚拟内存与物理内存的关系。
3. PCB:每个进程在自己的内核空间中,都有自己的PCB,在物理内存中的一个kernel维护多个的PCB,各个PCB之间彼此可见。
2.2 page页
1. page是内存管理的单位,假如 1 page = 4096 bytes
2. page可设置访问属性(R/W):物理内存中,kernel所在的page设置对cpu级别为0的可读可写,对cpu级别为3的不可读不可写了 此时,用户态就无法访问kernel.
3. malloc(1000):操作系统会分配一个page的空间,即4096bytes,此时利用了1000bytes,下次moclloc时,则会利用page中剩下的空间继续使用
2.3 进程切换
进程的切换时,需要保存当前的一些数据,比如代码执行到哪一行,这就是保存处理器现场,而每个进程都是拥有短暂时间的cpu执行权,这就利用到了分时复用cpu,具体解释如下:
1. 处理器现场:多个进程状态的切换,轮流使用同一个cpu,此时需要将处理器信息保存起来,以便恢复,保存在PCB中的内核栈中。
2. 分时复用cpu:每个cpu在某一时刻只能执行一个进程,多个进程需要运行时,为每个进程分配使用cpu的时间。当进程数越多,分配给每个进程的cpu执行时间就越少,系统就越卡顿。
2.4 父进程与子进程
1. 在shell执行命令时,其实是开启了子进程来执行命令,父进程是shell
2. 比如在终端输入ls,是通过fork和exec来实现父子进程中的关系
3. 进程相关函数
3.1 fork
3.1.1 作用
复制出一个子进程,实现多进程。
3.1.2 细节
空间:通过fork来复制进程,产生的子进程0-3G内容和父进程一样,而3G-4G的kernel中PCB的pid则不同
返回值: fork();方法返回两次,一次是向父进程返回子进程的pid,另一次是向子进程返回0
底层原理:
creat():创建进程
clone():克隆0-3G的内容
return :返回;
子进程诞生后执行的第一句就是return,返回0
执行:fork之前的代码不会被子进程执行,因为子进程clone了父进程的代码以及记录来代码运行到哪,所以前面已运行完的代码不会被执行。
3.1.3 代码使用
|
|
3.1.4 读时共享,写时复制(copy on write)
- 读时共享:通过fork出来的多个进程,在没有变量需要修改时,单纯读取时,是在物理内存中指向同一块空间。
节省物理内存
节省复制内容时所消耗的资源(此时消耗是每个进程唯一的PCB) - 写时复制:通过fork出来的多个进程,在需要写时,变量需要修改,此时才将进程的用户空间中的内存指向不同的物理内存。
3.1.5 文件权限
-rwsrwsrwt:07777
- 第一位rws中的s(4):以文件所有者的身份去运行程序;此时实际用户ID为真实用户ID,有效用户ID为文件所有者ID。
- 第二位rws中的s(2):以文件所有组的身份去运行程序
- 第三位rwt中的t(1):粘滞位;针对目录,除了文件创建者和root之外其他用户不可删除
存在意义 - s:以文件所有者身份运行程序,比如修改密码用命令passwd,存在与/usr/bin/passwd,权限是-rwsr-xr-x 则这个命令将以文件所有者身份运行,即root,此时便能修改真正的密码文件/etc/passwd了,不然普通用户是无法修改的。
- t:比如/tmp目录,权限为drwxrwxrwt,而临时目录/tmp是每个用户都有权限操作的,但又要防止其他用户删除了另一用户创建的目录,就需要用到粘滞位了。
- 大写与小写
s:小写,表示权限中有x,可执行权限
S:大写,表示权限中没有x,没有可执行权限
3.2 exec()
覆盖原有的APP代码段:
12345678910int main(void){printf("APP前置代码\n");execl("/bin/ls","ls","-l","exec.c",NULL);printf("APP后置代码\n");return 0;}执行结果为:APP前置代码-rw-rw-r-- 1 peisehn peisehn 173 10月 26 10:25 exec.c因为execl执行时,会替换掉原有APP的代码为自己方法中需要执行的命令代码,此时调用完execl后面的代码则不会执行,因为代码已经被替换掉了。
- 返回值为新线程返回值
如上代码,return 0不会被执行,真正返回值为execl中的命令返回值。 - exec族
execl:指定程序的路径(l:list列表的形式)
execlp:将从path环境变量中寻找程序,不需要指定路径(p:path路径)
execv:参数通过数组形式传入
execle:指定环境变量(e:evn环境变量)
execvp:结合上面
execve:结合上面(上面函数最终都是调用这个函数,系统函数,上面的函数是c提供的函数库) - shell执行原理
shell执行命令时,会通过fork复制出一个子进程,shell子进程再通过exec来将需要执行的命令程序中的代码段覆盖在
原有shell的子进程中,此时便实现了通过shell子进程来执行命令了。
3.3 wait()
- 父进程回收子进程的PCB:回收僵尸状态下的子进程
僵尸进程:进程的用户空间已被释放,而PCB还未被释放
存在意义:让父进程能够知道子进程是如何死的,得到子进程的一些信息,通过wait函数能够让父进程在子进程的pid,还没分配给其他进程时,就先通知父进程,让父进程能够得到相关信息作出进一步操作。 - 阻塞方法:成功释放返回子进程的pid,失败则返回-1
- waitpid(pid,status,options):可设置非阻塞方式回收子进程
pid:指定回收子进程的类型;如同一进程组的所有子进程
status:存储进程的终止信息
options:WNOHANG表示非阻塞–>返回0则没回收成功立即返回,返回-1则回收失败,返回其他则表示回收成功。 - 进程组:父子进程属于同个进程组,可通过kill来杀掉同个进程组的进程,需带上负号。kill -9 -23452
- 孤儿进程
当父进程结束时,子进程还没被父进程回收,此时子进程就会变成孤儿进程
孤儿进程将由1号进程(init进程)领养,即init进程成为孤儿进程的父进程,负责回收孤儿进程。