文章目录
进程
进程类型
- 前台进程(交互式进程):这些进程由终端会话初始化和控制;换句话说,需要有一个连接到系统中的用户来启动这样的进程;他们不是作为系统功能/服务的一部分自动启动;
- 后台进程(非交互式/自动进程):这些进程没有连接到终端;他们不需要任何用户输入;
守护进程
后台进程的特殊类型,他们在系统启动时启动,并作为服务一直运行;他们不会死亡;他们自发地作为系统任务启动(作为服务运行),但是他们能被用户通过init进程控制;
linux创建进程
当现有的进程在内存中完全拷贝一份自身的时候就会创建出一个新的进程;子进程会有和父进程一样的环境,只有进程ID不同。
在Linux中有两种常规方式创建进程:
- 使用system()函数-这个方法简单,但是比较低效而且具有明显的安全隐患。
- 使用fork()和exec()函数-较高级的方法但提供更好的灵活性、速度以及安全性
linux识别进程
由于Linux是一个多用户系统,意味着不同的用户可以在系统上运行各种各样的程序,内核必须唯一标识程序运行的每个实例。
程序由他的进程ID(PID)和它父进程的进程ID(PPID)识别,因此进程可以被分类为:
- 父进程-这些是运行时创建其他进程的进程。
- 子进程-这些是在运行时由其他进程创建的进程。
init进程
init进程是系统中所有进程的父进程,他是启动linux系统后第一个运行的程序;他管理着系统上的所有其他进程;由内核自身启动,因此理论上说他没有父进程。
init 进程的进程ID总是为1.他是所有孤儿进程的收养父母。
进程状态
- Running-此时正在运行(是系统中的当前进程)或准备运行(正在等待分配CPU单元)。®
- Waiting-在这个状态,进程正在等待某个事件的发生或系统资源。另外,内核也会区分两种不同的等待类型的等待进程:
- 可中断等待进程:可以被信号中断(S)
- 不可中断等待进程:正在等待硬性条件,不能被任何事件/信号中断(D)
- Stopped-在这个状态,进程已经被停止,通常是由于收到了一个信号。例如正在被调试的进程。(T)
- Zombie-该进程已经死亡,他已经停止了但是进程表中仍有他的条目,直到父进程调用wait4()系统调用后释放(Z);
查看进程:ps
### 以树结构显示结构
# -p 显示进程标识号
pstree -p [PID|USER]
# 树形显示所有进程
ps -axjf
### 显示所有进程信息,包含命令行
# 两者的主要区别显示风格不一致,aux是BSD风格,ef是System V格式,会显示全路径的进程名,因此我们尽量使用ef命令
ps -ef
ps -aux
查找进程ID:pidof
$ pidof init
1
终止进程:Kill
kill #通过进程ID来结束进程
killall #通过进程名字来结束进程
kill -SIGNAL PID
# 常用
kill -STOP [pid]
(17,19,23)停止一个进程,而并不消灭这个进程。
kill -CONT [pid]
(19,18,25)重新开始一个停止的进程。
kill -KILL [pid]
(9)强迫进程立即停止,并且不实施清理操作。
kill -SIGHUP [pid]
(1)挂起
kill -SIGINT [pid]
(2)键盘的中断信号
kill -SIGTERM [pid]
(15)发出终止信号
注意:SIGKILL 和 SIGSTOP 信号不能被捕捉、封锁或者忽略,但是,其它的信号可以。
查看进程工具-htop
第一区域:CPU、内存、Swap的使用情况;
第二区域:任务、线程、平均负载及系统运行时间的信息;平均负载有三个数字,代表的是过去的5分钟、10分钟和15分钟的平均负载而已,在单核的系统中平均负载为1表示的是百分之百的CPU利用率;uptime表示的是系统启动到当前的运行总时间;
第三区域:当前系统中的所有进程;各列说明:
PID:进程标志号,是非零正整数
USER:进程所有者的用户名
PR:进程的优先级别
NI:进程的优先级别数值
VIRT: 进程占用的虚拟内存值
RES: 进程占用的物理内存(驻留内存)值
SHR: 进程使用的共享内存值
S: 进程的状态,S表示休眠,R表示正在运行,Z(zombie)表示僵死状态,N表示该进程优先值是负数
CPU%:该进程占用的CPU使用率
MEM%:该进程占用的物理内存和总内存百分比
TIME+: 该进程启动后占用的总的CPU时间
COMMAND: 进程启动的启动命令名称
第四区域:
Shortcut Key | Function Key | Description | 中文说明 |
---|---|---|---|
h,? | F1 | Invoke htop Help | 查看htop使用说明 |
S | F2 | Htop Setup Menu | htop设定 |
/ | F3 | Search for a Process | 搜索进程 |
\ | F4 | Incremental process filtering | 增量进程过滤器 |
t | F5 | Tree View | 显示树形结构 |
<,> | F6 | Sort by a column | 选择排序方式 |
[ | F7 | Nice - (change priority) | 减少nice值,提高对应进程的优先级 |
] | F8 | Nice + (change priority) | 增加nice值,降低对应进程的优先级 |
k | F9 | Kill a Process | 可对进程传递信号 |
q | F10 | Quit htop | 结束htop |
命令行选项
-d | 设置延迟更新时间,-d单位微秒: htop -d 100(输出在1秒后刷新) |
---|---|
-u | 显示指定用户的进程:htop -u fzg |
-p | 只显示给定的PIDs |
-s | 依据指定的列排序: htop -s PID |
SIGCHLD
描述:
unix中的一种信号;
在一个进程或者停止时,将SIGCHLD信号发送给其父进程,按系统默认将忽略此信号。如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。信号的捕捉函数中通常调用wait函数以取得进程ID和其终止状态。
触发条件:
- 子进程终止时
- 子进程接收到SIGSTOP(19)信号
- 子进程处于停止态,接收到SIGCONT唤醒
作用:父进程借助SIGCHLD信号回收子进程
僵尸进程&孤儿进程
在unix中,正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。当一个进程完成他的工作终止之后,他的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。
概念
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由Init进程对他们完成状态收集工作。
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么进程描述符仍然保存在系统中。这种进程称为僵尸进程。
危害
Unix提供了一种机制可以保证只要父进程想要知道子进程结束时的状态信息,就可以得到。这种机制就是:在每个进程退出的时候,内核释放所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID、退出状态the termination status of the process、运行时间the amount of CPU time token by the process)。直到父进程通过wait/waitpid来取时才释放。这样就导致问题:如果不调用wait/waitpid的话,那么保留的那段信息就不会被释放,其进程号就会一直占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
孤儿进程是没有父进程的进程。每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,init进程会循环地wait()他已经退出的子进程。(相当于init会为孤儿进程做’收尸‘工作),因此孤儿进程并不会有什么危害。
任何子进程(init除外)在exit()之后,并非马上消失掉,而是留下一个zombie(僵尸状态)的数据结构,等待父进程处理,这是每个子进程在结束的时候都要经过的阶段,即子进程在exit()之后,父进程没来得及处理,此时ps查看该进程的状态便是“Z”。如果父进程及时处理,ps命令就不能及时看到,但不代表没有子进程没有经历僵尸状态。如果父进程在子进程结束之前推出,init进程将会以父进程的身份对僵尸状态的子进程进行处理。
僵尸进程案例:
例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。
解决方法
- 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。
- fork两次,父进程创建了子进程之后,子进程再创建孙进程,之后自己销毁,这样孙进程就交给Init进程了。