思考题:当你用ssh登录到一个linux机器,并且执行了某个hello.sh之后,有哪些进程参与了该过程?

linux系统架构

  • kernel mode
  • user mode
  • 内核态和用户态的区别

什么是进程

  • 进程是运行的程序
  • process 是对 processor 虚拟化,通过时间片

进程都有uid

nginx访问某个目录,Permission denied

进程都有pid

  • $$

进程都有父进程

  • 准确来说,除了pid为0的进程之外,其他进程都有父进程
  • 有时候,你用kill命令杀死了一个进程,但是立马你就发现这个进程又起来了。你就要看看,这个进程是不是有个非init进程的父进程。一般这个进程负责监控子进程,一旦子进程挂掉,就会去重新创建一个进程。所以你需要找到这个父进程的Id,先把父进程kill掉,然后在kill子进程。

进程是一棵树

#!/bin/bash
echo "pid is $$"
times=0

while true
do
	sleep 2s;
	let times++;
	echo $times hello;
done
➜  ~ pstree 24601
sshd─┬─3*[sshd───zsh]
     ├─sshd───zsh───pstree
     └─sshd───zsh───world.sh───sleep

进程都有生命周期

  • 创建
  • 销毁

进程都有状态

  • runing 进程占用CPU, 正在执行指令
  • ready 进程所有需要的资源都已经就绪,等待进入CPU执行
  • blocked 进程被某些事件阻断,例如IO。

进程的状态转移图

进程都有打开的文件描述符

使用lsof命令,可以查看某个进程所打开的文件描述符

/proc/pid/fd/目录下也有文件描述符

lsof -c 进程名lsof -p 进程号lsof filename # 查看某个文件被哪个进程打开**

[root@localhost ~]# lsof -c rtpproxy
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
rtpproxy 2073 root  cwd    DIR              253,0     4096      128 /
rtpproxy 2073 root  rtd    DIR              253,0     4096      128 /
rtpproxy 2073 root  txt    REG              253,0   933247 18295252 /usr/local/bin/rtpproxy
rtpproxy 2073 root  mem    REG              253,0  2127336 33617010 /usr/lib64/libc-2.17.so
rtpproxy 2073 root  mem    REG              253,0    44448 33617041 /usr/lib64/librt-2.17.so
rtpproxy 2073 root  mem    REG              253,0    19776 34757658 /usr/lib64/libdl-2.17.so
rtpproxy 2073 root  mem    REG              253,0  1139680 34757660 /usr/lib64/libm-2.17.so
rtpproxy 2073 root  mem    REG              253,0   144792 33617035 /usr/lib64/libpthread-2.17.so
rtpproxy 2073 root  mem    REG              253,0   164112 33595530 /usr/lib64/ld-2.17.so
rtpproxy 2073 root    0u   CHR                1,3      0t0     1028 /dev/null
rtpproxy 2073 root    1u   CHR                1,3      0t0     1028 /dev/null
rtpproxy 2073 root    2u   CHR                1,3      0t0     1028 /dev/null
rtpproxy 2073 root    3u  IPv4              17641      0t0      UDP 192.168.40.100:7890
rtpproxy 2073 root    4u  unix 0xffff880079260000      0t0    17642 socket
rtpproxy 2073 root    8u  IPv4           72592335      0t0      UDP 192.168.40.100:25257

进程都有资源限制

/proc/pid/limits

以rtpproxy为例子,rtpproxy的pid为2073, /proc/pid/limits文件记录进程的资源限制

进程都有环境变量

/proc/pid/environ

进程都有参数

/proc/pid/cmdline

rtpproxy-A192.168.40.100-l192.168.40.100-sudp:192.168.40.1007890-F-m20000-M40000-L20000-dDBUG[root@localhost 2073]#

进程都有名字

/proc/2073/status

Name:	rtpproxy
State:	S (sleeping)
Tgid:	2073
Ngid:	0
Pid:	2073
PPid:	1
TracerPid:	0
Uid:	0	0	0	0
Gid:	0	0	0	0

进程皆有退出码

  • 非0的退出码一般是异常退出
  • $?
[root@localhost 2073]# cat "test"
[root@localhost 2073]# echo $?
1
[root@localhost 2073]# echo $?
0

进程可以fork

孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程

 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。 僵尸进程占用进程描述符,无法释放,会导致系统无法正常的创建进程。

> cat /proc/sys/kernel/pid_max
32768

进程间通信

进程之间的所有资源都是完全隔离的,所以进程之间如何通信呢?

在liunx底层,有个套接字API

SOCKET socket (int domain, int type, int protocol)
  • domain 表示域,一般由两个值
    • AF_INET 即因特网
    • AF_LOCAL 用于同一台机器上的进程间通信
  • type 表示类型
    • SOCK_STREAM 提供可靠的、全双工、面向链接的字节流,一般就是TCP
    • SOCK_DGRAM 提供不可靠、尽力而为的数据报服务,一般就是UDP
    • SOCK_RAW 允许直接访问IP层原生的数据报

也就是说,进程间通信,实际上也是用的socket

守护进程

守护进程一般是后台运行的进程,例如sshd, mysqld, dockerd等等,他们的特点就是他们的ppid是1, 也就是说,守护进程也是孤儿进程的一种。

root      9696     1  0 Oct06 ?        00:05:16 /usr/sbin/sshd -D

idle进程与init进程

Linux下有3个特殊的进程**,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)**

  • idle进程由系统自动创建, 运行在内核态。idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换
  • init进程由idle通过kernel_thread创建,在内核空间完成初始化后, 加载init程序, 并最终用户空间。由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程
  • Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。
  • kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理

参考:https://blog.csdn.net/gatieme/article/details/51484562

线程

ps -m可以在进程之后显示线程。线程的tid也会占用一个/proc/tid目录,和进程的/proc/pid 目录没什么区别。

只不过进程的Tgid(线程组Id)是自己的pid, 而其他线程的Tgid是主线程的pid。

ps -em -o pid,tid,command | grep rtpproxy -A10
 2112     - rtpproxy -l 192.168.40.101 -s udp:192.168.40.101 7890 -F -m 20000 -M 40000 -L 20000 -d DBUG
    -  2112 -
    -  2113 -
    -  2114 -
    -  2115 -
    -  2116 -
    -  2117 -
    -  2118 -

进程与线程的区别

关于/proc目录

proc目录是一个虚拟的文件系统,实际上是内核的数据结构的映射。里面的大部分的文件都是只读的,只有少部分是可写的。

关于进程运行时信息,都可以在这个目录找到。

下面的链接详细的介绍了每个目录的作用。

以下的几个文件是比较重要的,着重说明一下。

  • cmdline 执行参数
  • environ 环境变量
  • ** exe -> /usr/local/bin/rtpproxy  可执行文件位置**
  • ** fd 文件描述符信息**
  • ** limits 资源限制**
  • oom killer机制:杀掉最胖的那个进程
    • oom_adj
    • oom_score
    • oom_score_adj
  • status 状态信息
dr-xr-xr-x. 2 root root 0 Jan 14 15:56 attr
-rw-r--r--. 1 root root 0 Jan 14 15:56 autogroup
-r--------. 1 root root 0 Jan 14 15:56 auxv
-r--r--r--. 1 root root 0 Nov  6 17:59 cgroup
--w-------. 1 root root 0 Jan 14 15:56 clear_refs
-r--r--r--. 1 root root 0 Nov  6 10:26 cmdline
-rw-r--r--. 1 root root 0 Nov  6 17:59 comm
-rw-r--r--. 1 root root 0 Jan 14 15:56 coredump_filter
-r--r--r--. 1 root root 0 Jan 14 15:56 cpuset
lrwxrwxrwx. 1 root root 0 Jan 14 15:56 cwd -> /
-r--------. 1 root root 0 Jan 14 15:56 environ
lrwxrwxrwx. 1 root root 0 Nov  6 17:59 exe -> /usr/local/bin/rtpproxy
dr-x------. 2 root root 0 Jan 14 15:56 fd
dr-x------. 2 root root 0 Jan 14 15:56 fdinfo
-rw-r--r--. 1 root root 0 Jan 14 15:56 gid_map
-r--------. 1 root root 0 Jan 14 15:56 io
-r--r--r--. 1 root root 0 Jan 14 15:56 limits
-rw-r--r--. 1 root root 0 Nov  6 17:59 loginuid
dr-x------. 2 root root 0 Jan 14 15:56 map_files
-r--r--r--. 1 root root 0 Jan 14 15:56 maps
-rw-------. 1 root root 0 Jan 14 15:56 mem
-r--r--r--. 1 root root 0 Jan 14 15:56 mountinfo
-r--r--r--. 1 root root 0 Jan 14 15:56 mounts
-r--------. 1 root root 0 Jan 14 15:56 mountstats
dr-xr-xr-x. 5 root root 0 Jan 14 15:56 net
dr-x--x--x. 2 root root 0 Jan 14 15:56 ns
-r--r--r--. 1 root root 0 Jan 14 15:56 numa_maps
-rw-r--r--. 1 root root 0 Jan 14 15:56 oom_adj
-r--r--r--. 1 root root 0 Jan 14 15:56 oom_score
-rw-r--r--. 1 root root 0 Jan 14 15:56 oom_score_adj
-r--r--r--. 1 root root 0 Jan 14 15:56 pagemap
-r--r--r--. 1 root root 0 Jan 14 15:56 personality
-rw-r--r--. 1 root root 0 Jan 14 15:56 projid_map
lrwxrwxrwx. 1 root root 0 Jan 14 15:56 root -> /
-rw-r--r--. 1 root root 0 Jan 14 15:56 sched
-r--r--r--. 1 root root 0 Nov  6 17:59 sessionid
-rw-r--r--. 1 root root 0 Jan 14 15:56 setgroups
-r--r--r--. 1 root root 0 Jan 14 15:56 smaps
-r--r--r--. 1 root root 0 Jan 14 15:56 stack
-r--r--r--. 1 root root 0 Jan 14 15:56 stat
-r--r--r--. 1 root root 0 Jan 14 15:56 statm
-r--r--r--. 1 root root 0 Nov  6 10:26 status
-r--r--r--. 1 root root 0 Jan 14 15:56 syscall
dr-xr-xr-x. 9 root root 0 Jan 14 15:56 task
-r--r--r--. 1 root root 0 Jan 14 15:56 timers
-rw-r--r--. 1 root root 0 Jan 14 15:56 uid_map
-r--r--r--. 1 root root 0 Jan 14 15:56 wchan

工具简介

ps

ps有三种风格的使用方式,我们一般使用前两种

  • Unix风格 参数以-开头,如-a
  • BSD风格,直接用参数 如a
  • GUN风格,以–开头

常用的有

  • ps -ef
  • ps aux
    • VSZ 虚拟内存,单位kb
    • RSS 物理内存,单位kb
2112 ps -ef | head
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2018 ?        01:57:34 /usr/lib/systemd/systemd --system --deserialize 23
root         2     0  0  2018 ?        00:00:44 [kthreadd]
root         3     2  0  2018 ?        00:05:44 [ksoftirqd/0]
root         7     2  0  2018 ?        00:08:04 [migration/0]
root         8     2  0  2018 ?        00:00:00 [rcu_bh]
root         9     2  0  2018 ?        00:00:00 [rcuob/0]
root        10     2  0  2018 ?        00:00:00 [rcuob/1]
root        11     2  0  2018 ?        00:00:00 [rcuob/2]
root        12     2  0  2018 ?        00:00:00 [rcuob/3]

2112 ps aux | head
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 193524  3572 ?        Ss    2018 117:34 /usr/lib/systemd/systemd --system --deserialize 23
root         2  0.0  0.0      0     0 ?        S     2018   0:44 [kthreadd]
root         3  0.0  0.0      0     0 ?        S     2018   5:44 [ksoftirqd/0]
root         7  0.0  0.0      0     0 ?        S     2018   8:04 [migration/0]
root         8  0.0  0.0      0     0 ?        S     2018   0:00 [rcu_bh]
root         9  0.0  0.0      0     0 ?        S     2018   0:00 [rcuob/0]
root        10  0.0  0.0      0     0 ?        S     2018   0:00 [rcuob/1]
root        11  0.0  0.0      0     0 ?        S     2018   0:00 [rcuob/2]
root        12  0.0  0.0      0     0 ?        S     2018   0:00 [rcuob/3]

ps 查看线程

2118 ps -em -o pid,tid,command  | grep rtpproxy -A 10
 2112     - rtpproxy -l 192.168.40.101 -s udp:192.168.40.101 7890 -F -m 20000 -M 40000 -L 20000 -d DBUG
    -  2112 -
    -  2113 -
    -  2114 -
    -  2115 -
    -  2116 -
    -  2117 -
    -  2118 -

cat /proc/2112/status
Name:	rtpproxy
State:	S (sleeping)
Tgid:	2112
Ngid:	0
Pid:	2112
PPid:	1
TracerPid:	0
Uid:	0	0	0	0
Gid:	0	0	0	0
FDSize:	16384
Groups:	0
VmPeak:	  390896 kB
VmSize:	  259824 kB
VmLck:	       0 kB
VmPin:	       0 kB
VmHWM:	  121708 kB
VmRSS:	    3532 kB
VmData:	  246120 kB
VmStk:	     136 kB
VmExe:	     176 kB
VmLib:	    3092 kB
VmPTE:	     316 kB
VmSwap:	    2272 kB
Threads:	7
SigQ:	2/15086
SigPnd:	0000000000000000
ShdPnd:	0000000000000000
SigBlk:	0000000000000000
SigIgn:	0000000000001000
SigCgt:	0000000187804a03
CapInh:	0000000000000000
CapPrm:	0000001fffffffff
CapEff:	0000001fffffffff
CapBnd:	0000001fffffffff
Seccomp:	0
Cpus_allowed:	f
Cpus_allowed_list:	0-3
Mems_allowed:	00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:	0
voluntary_ctxt_switches:	259223710
nonvoluntary_ctxt_switches:	2216

nestat

  • netstat -nulp 
  • netstat -ntulp
  • netstat -nap

lsof

Linux下所有信息都是文件,那么查看打开文件就比较重要了。 lisf open file, 查看打开的文件

  • lsof -c processName  按照进程名查看
  • lsof -c pid  按照pid查看
  • lsof file  查看文件被哪些进程打开
  • losf -i:8080 查看8080被那个进程占用

top

  • top
  • 1
  • P
  • M

参考

附件书籍

proc(5) - Linux manual page.pdfCommand Line Text Processing - Sundeep Agarwal.pdfHow Linux Works _ What Every Superuser Sho - Brian Ward(Author).pdfOperating Systems three easy pieces - Unknown.pdf[Sarath Lakshman] Linux Shell Scripting Co - Unknown.pdftcp_ipGao Xiao Bian Cheng __Gai Shan Wang - Unknown.pdf