注: 学习宋宝华课程总结
进程是资源封装管理的单位,资源指占用的内存,文件系统,信号及处理方法。线程是调度的单位,进程的区别是资源,资源是隔离的,进程把资源描述清楚就可以了
Process Control Block(PCB) 进程控制块, 在不同操作系统中用于描述进程,在 Linux 的 PCB 就是用 task_struct 来描述。描述来 task_struct 的部分成员
当前路经是在 fs_struct 中的
struct fs_struct {
int users;
spinlock_t lock;
seqcount_t seq;
int umask;
int in_exec;
struct path root, pwd;
};
files 进程打开的文件描述符 fd_array
/*
* Open file table structure
*/
struct files_struct {
/*
* read mostly part
*/
atomic_t count;
struct fdtable __rcu *fdt;
struct fdtable fdtab;
/*
* written part on a separate cache line in SMP
*/
spinlock_t file_lock ____cacheline_aligned_in_smp;
int next_fd;
unsigned long close_on_exec_init[1];
unsigned long open_fds_init[1];
struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};
$ cat /proc/sys/kernel/pid_max
32768
:(){:|: & }; :
# : 函数名为冒号
# () 函数参数定义
# {} 函数定义
# :调用自己
# |:递归调用自己
# & 后台执行
# ; 函数结束
# : 调用函数
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 15225
max locked memory (kbytes, -l) 16384
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 15225 ##<<<<<
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
安卓的 2.2.1 之前的版本被发现一个漏洞,很容易就被一键 root,安卓的调试软件 adb 刚开始时有 root 权限,之后 adb 调用 api setuid(shell) 把自己从 root用户降为 shell 用户。谷歌的工程师在调用时没有检查 setuid 的返回值,即默认 setuid 总是可以成功。黑客们利用 uid 数量有限制的属性,将 shell 用户内的pid 进程全部用完,这样调用 setuid 时是无法成功的,但因为没有检查返回值,导致 adb 调用 setuid(shell) 后没有降权成功,还是有 root 权限。这就是 Android著名的提权漏洞: rageagainstthecage。2.2 之后的安卓版本修复了此漏洞,方法是检查 setuid 的返回值。Android提权漏洞分析——rageagainstthecage
一个进程 fork 出子进程后,从 linux 内核的角度看,对应的 pid 肯定不一样。但是为了符合 POSIX 的标准要求, POSIX 要求规定同一个父进程 fork 出的子进程,调用 getpid 返回的 pid 的号必须是一样的,我们用 top 命令查看进
程可以看到 fork 出的子进程与父进程的 Pid 号是一样的。 linux 实现的原理就是通过增加一个 tgid 来实现父子进程调用 getpid 时返回值都一样的效果。
task_struct 与 task_struct 之间的关系是什么?
在 linux 代码中会涉及各种对 task_struct 的引用关系,比如调度算法中会将task_struct 挂在链表上,父子进程的关系用树来描述, CFS 调度算法会用到红黑树,通过 pid 查找进程则是用 hash 表的结构。可以通过 pstree 命令
进行查看,父进程回收子进程,父对子的监控。其对应的数据结构:
每种数据结构选择都是根据应用场景的需求来选择实现目的效率最高的数据结构
进程运行时的 3 个基本状态:
操作系统包括实时系统对应进程一般都有 3 个状态,进程在有 CPU 时对应运行态,无 CPU 时对应就绪态和睡眠态。就绪态指所有资源都准备好,只要有 CPU 就可以运行了。睡眠指有资源还未准备好,比如读串口数据时,数据还未发送。此时有 CPU 也无法运行,需要等资源准备好后变成就绪态,然后得到 CPU 后才能变成运行态,其转换关系
僵尸是什么?
资源释放了, task_struct 还在,父进程可以查到子进程的死因
子进程死了之后,linux 会自动回收资源
什么是内存泄露?
内存泄露指随着时间的增长,进程的内存使用呈现线性增长的情况,指的是进程一直在运行,运行中申请了内存,但使用完后并没有释放,运行期间每次都申请内存而不释放导致系统内存越来越少的情况。这里要理解内存泄露的原因不可能是进程死了,内存没释放。因为进程死了之后就变成僵尸, Linux会自动将进程中申请的资源全部释放,只留下 task_struct 让父进程 wait 来查看状态。不可能再占用内存。
如何观察内存泄漏?
痛多多点检测法,多点采样,可以看到内存是的图像是震荡向上的。没内存泄漏的
内存是震荡收敛的一个图形
参看 process_codes/day1/life_period.c 代码
waitpid 可以清除僵尸进程,如果没有走到 wait 一直处于僵尸状态,处于僵尸状态的进程是无法 kill 掉的, 直接杀死父进程可以回收处于僵尸态的子进程
暂停状态是进程在运行过程中,通过外部 bash 命令强制让进程进入的状态。通过这种方法可以指定进程的 CPU 占用率。后面我们通常用 cgroup 的方法来实现,这里仅作了解。
如何进入停止态? ctrl + z 进入停止状态,fg/bg可以调控前台/后台运行
# #作业控制的命令
# ctrl + z, fg/bg
$ cpulimit
$ cpulimit -l 20 -p 10111
# 限制 pid 为 10111 程序的 CPU 使用率不超过 20%
fork 返回值, 父进程返回子进程的 PID, 子进程返回 0
打印几个hello