Linux进程控制详解

news2024/11/24 22:29:16

目录

  • 前言
  • 一、进程创建
    • 1.1 fork函数初识
    • 1.2 写时拷贝
    • 1.3 fork常规用法
    • 1.4 fork调用失败的原因
  • 二、进程终止
    • 2.1 进程终止时,操作系统做了什么??
    • 2.2 进程终止的常见方式有哪些??
    • 2.3 如何用代码终止一个进程
  • 三、进程等待
    • 3.1 进程等待的必要性
    • 3.2 进程等待的方法
      • wait方法
      • waitpid方法
  • 补充知识
  • 四、waitpid进一步讲解
  • 五、进程替换
    • 5.1 概念及原理
    • 5.2 操作
      • 5.2.1 不创建子进程
        • execl
      • 5.2.2 创建子进程
        • execv
        • execlp
        • execvp
        • execle + 执行其他的C二进制程序
        • 执行其他语言的程序
    • 5.3 execve
  • 六、自己实现一个简易的shell程序
    • 6.1 函数介绍
    • 6.2 myshell.c完整代码
  • 总结

前言

前面的文章都是关于进程概念的学习,今天我们就要进入一个新的章节,关于进程控制的解析,这其中我会穿插着前面已经讲过的知识,在以前知识的基础上学习新的知识,如果其中有哪里不懂的地方,大家可以去看一看我前面的文章,下面我们一起来学习新的知识吧。

一、进程创建

1.1 fork函数初识

在Linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
在这里插入图片描述
进程调用fork,当控制转移到内核中的fork代码后,内核做:
1.分配新的内存块和内存数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表中
4.fork返回,开始调度器调度
在这里插入图片描述
fork之后,父子进程代码的共享情况

在这里插入图片描述

1.2 写时拷贝

通常,父子代码共享,父子在不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式变为各自一份副本,具体可见下图
在这里插入图片描述
写时拷贝的好处: 因为有写时拷贝技术的存在,所以,父子进程得以彻底分离!完成了进程独立性的技术保证!
写时拷贝是一种延时申请技术,可以提高整机内存的使用率

1.3 fork常规用法

1.一个父进程希望复制自己,使父子进程同时执行不同的代码段。
2.一个进程要执行不同的程序

1.4 fork调用失败的原因

1.系统中有太多的进程
2.实际用户的进程数超过了限制(我们平时在写代码的时候,进程数其实是有限的)

二、进程终止

2.1 进程终止时,操作系统做了什么??

当然是释放进程申请的相关内核数据和对应的数据和代码,本质就是释放系统资源。

2.2 进程终止的常见方式有哪些??

a.代码跑完,结果正确
b.代码跑完,结果不正确
c.代码没有跑完,程序崩溃了(这部分涉及到了信号部分,我们先说一点点,后面再详细的说)
这里我们主要分析a、b两条内容,我先提一个问题:
大家平时在写C/C++程序的时候,一定都会写main函数,main函数最后都会有return 0,那么这里的return 0的含义是什么呢?为什么总是0,main函数返回的意义是什么???
在这里插入图片描述
在做下面的实验前我再补充一个小的知识点
echo $?:获取最近一个进程,执行完毕的退出码。
在这里插入图片描述
现在相信大家已经知道main函数最后的return 0是什么含义了,每一个退出码都有着不同的含义,我们通过下面的这个函数把C语言中的退出码是什么含义打印一下看看。
在这里插入图片描述
在这里插入图片描述
我们今天学习完退出码的概念,大家以后写代码的时候要可以将其应用起来,大家一起看下面的这个例子

int main()
{
	FILE* fp = fopen();
	if(fp == NULL)
		return 1;
	return 0;
}

当我们需要打开一个文件的时候,就可以使用上述的if判断语句来判断我们的这个文件是否被成功打开,当程序的退出码为1的时候,就是不允许操作,即这个文件打开失败,这样就可以更快地排查错误。


a、b两条内容分析完后,我们还要谈一谈c的内容,代码没有跑完,程序崩溃了。
在这里插入图片描述

2.3 如何用代码终止一个进程

什么是一个正确的终止???
1.return
main函数内的return语句,就是终止进程的,return 退出码
只有在main函数返回,进程退出
调用一些其他的函数,return则是退出当前的函数并返回一个值。
2.exit,C语言层面的函数
在这里插入图片描述
在这里插入图片描述
通过上面的情况再与return进行比较我们可以发现:
return只有在main函数中有结束进程的作用,exit在代码的任何位置调用,都表示直接终止进程!!!
3._exit,系统层面的函数
在这里插入图片描述
上面图片中的_exit与_Exit的作用类似,我们只用_exit来举例子,让大家看一下与_exit与exit有什么不同之处
在这里插入图片描述

从图中大家可以看到_exit()与exit()的区别,在平时写代码的时候还是建议大家使用exit()函数。
在这里插入图片描述

三、进程等待

在讲述进程等待前我们先来试想两种场景
1.子进程退出,父进程不管子进程,子进程就要处于僵尸状态,一直处于僵尸状态不释放资源,就会导致内存泄漏
2.父进程创建了子进程,是要让子进程完成一些任务的,那么子进程把任务完成得怎么样?父进程需不需要关心,如果需要,怎么得知子进程的情况,如果不需要,又要怎么处理呢?
子进程把任务完成的情况也是分为三种情况:
a.代码跑完,结果正确
b.代码跑完,结果不正确
c.代码没有爬完,程序崩溃了

3.1 进程等待的必要性

1.子进程退出,父进程如果不管不顾,就可能造成僵尸进程的问题,进而造成内存泄漏。另外,进程一旦变成僵尸状态,那就刀枪不入,即使是kill -9也无能为力,因为谁也没有办法杀去一个已经死去的进程。
2.最后,父进程派给子进程的任务完成的如何,我们其实是需要知道的,比如子进程运行完成后,结果对不对,或者最后是否正常退出,都是我们需要考虑的问题


父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

3.2 进程等待的方法

我们先来看一下不让父进程去回收子进程的资源的情景,来进行一下对比
在这里插入图片描述
在上面的代码中,我们使用fork()函数创建了一个子进程,然后让其循环五次,打印同一行代码,循环结束后,结束进程,而父进程则一直进行循环,这样当子进程结束后,父进程还在死循环,无法收集子进程的资源,那么子进程就将成为僵尸进程。下面我们来看结果
在这里插入图片描述

这样就导致了僵尸进程的产生,那么如何解决这个问题呢?

wait方法

主要验证回收僵尸进程的问题
wait接口,我们可以通过man 2 wait来查询关于wait的信息
在这里插入图片描述
当然其中也有waitpid的信息。
下面我们先来简单认识一下wait()
在这里插入图片描述
下面我们来看一下实验代码以及运行结果
实验一:我们先来看一下如果父进程属于睡眠状态不调用wait函数,子进程是不是还是变为僵尸进程
在这里插入图片描述
运行结果分析
在这里插入图片描述
实验二:当父进程不处于睡眠状态时,又是一种怎样的情景
在这里插入图片描述
运行结果分析
在这里插入图片描述

父进程:wait时,父进程处于阻塞式等待,父进程处于阻塞态,等子进程退出。当子进程退出时,操作系统再将父进程唤醒,放到运行队列里,由父进程调用wait函数,再返回。
父进程处于阻塞式的等待意味着: 子进程不退出,父进程也不退出

waitpid方法

在这里插入图片描述
进程异常退出或者崩溃,本质是操作系统杀掉了你的进程!!
操作系统如何杀掉的呢?本质是通过发送信号的方式!
下面我们来看一下实验代码以及运行结果
实验一:子进程正常结束
在这里插入图片描述
运行结果
在这里插入图片描述
实验二:子进程非正常结束(1)
注: 当进程非正常结束时,进程的退出码就没有任何意义,主要观察进程收到的信号编号
在这里插入图片描述
运行结果
在这里插入图片描述
关于信号的信息我们可以通过kill -l(小写的l)来查看
其中1~31为普通信号,没有0号信号
在这里插入图片描述
实验二:子进程非正常结束(2)
在这里插入图片描述
运行结果
在这里插入图片描述
实验二:子进程非正常结束(3)
程序异常,不光光是内部的代码有问题,也可能是外力杀掉了子进程(子进程代码有没有跑完并不确定)
在这里插入图片描述
上面的代码我们让子进程死循环,那么这个进程就会一直运行
在这里插入图片描述
此时我们在另一个窗口将该进程杀掉
在这里插入图片描述
最后父进程收到的信号编号就是9号信号
在这里插入图片描述
总结:
1.如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息
2.如果在任意时刻调用wait/waitpid,子进程存在企鹅撑场运行,则进程可能阻塞
3.如果不存在该子进程,则立即出错返回
4.往后我们编写多进程,基本的写法就是fork + wait/waitpid

补充知识

1.父进程通过wait/waitpid可以拿到子进程的退出结果,为什么要用wait/waitpid函数呢?可不可以使用全局变量?
答:不可以
因为我们在前面就说过进程具有独立性,那么数据就要发生写时拷贝,父进程无法拿到子进程内的数据,更何况是信号了
2.既然进程是具有独立性的,那进程退出码也应该是子进程的数据,父进程凭什么能拿到呢,wait/waitpid究竟做了什么事情?
答:wait/waitpid的本质其实是读取子进程的task_struct结构。
3.这又和task_struct结构有啥关系呢??
其实最后进程退出的时候,一个进程的退出码和退出信号会被写到task_struct中(task_struct结构中有exit_pid,exit_signal两个变量),僵尸进程也是一样的,子进程退出,那么他的代码和数据就不会被运行和应用,就可以释放相关的数据,但是至少他会保留该进程的PCB信息,task_struct里面保留了任何进程退出时的退出结果信息, wait/waitpid读取task_struct结构后再将exit_pid,exit_signal(两个字段)进行位操作设置到传入的status变量中,然后再返回出来,就可以得到子进程的信号编号和退出码
4.wait/waitpid有这个权利么?
答:肯定有这个权利
wait/waitpid属于系统调用函数,本质是操作系统去拿取task_struct中的数据,而task_struct是内核数据结构对象,所以操作系统可以对其进行读取也就没有任何问题了。

四、waitpid进一步讲解

在这里插入图片描述
options中的WNOHANG选项。
WNOHANG选项,代表父进程非阻塞等待!
在这里插入图片描述
非阻塞等待:我们的父进程通过调用waitpid来进行等待,如果子进程没有退出,我们waitpid这个系统调用会立刻返回。
了解了上面的宏定义后,我们先来使用一下,顺便再结合而代码详细介绍一下我们上面所讲的内容
在这里插入图片描述
下面我们来看一下waitpid的伪代码
在这里插入图片描述
阻塞等待我们已经讲述完毕,后面就是非阻塞等待
非阻塞等待我们还是通过代码来演示
其实非阻塞等待的最大意义在于:
当子进程还在处理自己事情的时候,父进程不需要进入阻塞状态,父进程依然可以去做一些自己的事情,当子进程处理完自己的事情以后,父进程再去回收子进程的资源和数据。
在这里插入图片描述
运行结果:
在这里插入图片描述
通过上面的运行结果,我们可以看到,当子进程还在运行的时候,父进程可以腾出来时间来处理自己的任务,这就是非阻塞等待的好处。
如果未来编写网络代码的话,大部分都是IO类别,会不断面临阻塞和非阻塞的接口

五、进程替换

5.1 概念及原理

fork()之后,父子代码是共享的,数据写时拷贝,各自一份,父子进程各自执行父进程代码的一部分,但是如果子进程就想执行一个全新的程序呢?
进程的程序替换可以完成这个功能,程序替换是通过特定的接口,加载磁盘上的一个权限的程序(代码和数据),加载到调用进程的地址空间中,阿里让子进程执行其他的程序


可能上面说的内容比较抽象,大家不好理解,那么我们下面就通过画图的方式,来剖析一下进程替换的原理

在这里插入图片描述

5.2 操作

关于进程替换的函数有以下六个,看似很复杂,其实还是比较好理解的
在这里插入图片描述
下面我们先来进行一下基本的演示
1.不创建子进程
2.创建子进程
从这两个方面介绍,同时只使用最简单的exec函数,先看一看进行进程替换后会发生什么事情
后面我们会详细展开其他函数的用法

5.2.1 不创建子进程

execl

第一个我们要介绍的函数就是execl
在这里插入图片描述
其实该函数的可变参数列表可以参考我们平时最常用的命令行参数
下面我们就以平时用的最多的ls命令进行举例,先来看一下ls命令
在这里插入图片描述
红框内就是ls的路径,那么我们下面就来用ls命令进行进程替换,先看代码
在代码中,我在main函数的开始和结尾都加上了一句打印,这样就可以看到进程进行的情况,然后中间去调用函数进行进程替换。
在这里插入图片描述
代码运行结果
在这里插入图片描述
通过代码运行的结果,我们可以看到一些问题
程序刚开始运行的时候,打印了第一句代码,后面进行了程序替换,执行了ls的命令,同时也将其对应的结果打印了出来,但是最后面的一行代码并没有被打印出来,这个就是程序替换的特性
针对代码结果进行分析
1.为什么最后一句代码不打印呢??
execl是程序替换,调用该函数成功之后,会将当前进程的所有代码和数据都进行替换,包括已经执行的和没有执行的
简单来说,就是执行execl之后,execl之前和之后的代码都会被替换掉,只不过之前的代码运气比较好,在替换之前就已经执行完了,所以才有了最开始的打印结果。而后面所有的代码,全都不会执行
2.execl的返回值
在这里插入图片描述
我们看手册的介绍可以得知,如果调用失败,会返回-1,但是调用成功,并不会返回值,这又是为什么呢?
为什么调用成功没有返回值呢?
这个其实也很好理解,因为execl根本不需要进行函数返回值判定,如果替换成功,execl会将main函数中包含execl本身的代码全部都替换掉,前面用于接受返回值的数据也都已经被替换了,所以也就不需要有返回值了。


在这里插入图片描述
如果想让我们打印的字体也颜色的话,就可以看ls的内容再加一些代码
在这里插入图片描述
在这里插入图片描述
讲解后面知识之前,我们先来回忆一下之前的内容
加载新程序之前,父子的数据和代码的关系:
代码共享,数据写时拷贝
当子进程加载新程序的时候,就是一种写入,那么这个时候代码要不要进程写时拷贝呢?
一定会进行写时拷贝,父子进程的代码必须要分离
所以当我们调用execl函数的时候,父子进程在代码和数据上就彻底分开了。

5.2.2 创建子进程

为什么要创建子进程呢?
为了不影响父进程,我们想让父进程聚焦在读取数据,分析数据,指派进程执行代码的功能,如果不创建,那么我们替换的进程只能是父进程,如果创建了,替换的进程就是父进程,从而不会影响父进程


在上面我们已经看了execl的使用,所以这里就不多说了,关于exec系列还有几个函数,我们一起来看一下

execv

在这里插入图片描述
实验代码及结果
在这里插入图片描述

execlp

在这里插入图片描述
在这里插入图片描述
实验代码及结果
在这里插入图片描述

execvp

在这里插入图片描述
实验代码及结果
在这里插入图片描述


以上的代码基本都没有什么问题,那么我们来探究一个新的问题
1.如何执行其他我自己写的C、C++二进制程序
2.如何执行其他语言的程序

execle + 执行其他的C二进制程序

在这里插入图片描述
Makefile操作延伸
在这里插入图片描述
在Makefile中替换单词
例如:将Makefile中所有的exec替换为myshell
1.先按Esc
2.输入 :(英文冒号)
3.%s/exec/myshell/g + 回车

exec.c代码
在这里插入图片描述
mycmd.c代码
在这里插入图片描述
经过我们上面的代码,成功地实现了一个程序调用另一个程序
回顾 + 总结: 环境变量具有全局属性,可以被子进程继承下去,通过execle就可以将父进程的环境变量传给子进程

执行其他语言的程序

我们这里就简单的演示一下执行python语言的程序和执行shell程序
python代码,只输出一下,能够看到我们调用了即可
在这里插入图片描述
shell程序代码
在这里插入图片描述
运行python: python test.py
运行test.sh: bash test.sh
在这里插入图片描述
如果我们使用shmod + x test.py也可以执行python程序,这句话的意思就是给test.py加上可执行权限,就可以将test.py变为可执行程序,那么也就能直接执行该程序,了解了这些以后,下面开始进行一下简单的调用
1.调用python程序
在这里插入图片描述
1.调用shell程序
在这里插入图片描述
以上就是调用其他程序的全部内容。大家只需要了解就可以了

5.3 execve

在这里插入图片描述
其实在程序替换中,操作系统只提供了这一个接口,这个才是真正的系统调用接口。前面讲的函数是系统提供了基础封装(C语言做的封装),从而用来满足上层的不同的调用场景,上面的函数接受的数据经过整合后再传给execve函数
execve没有带p,所以需要带全路径

六、自己实现一个简易的shell程序

我们在自己写shell的时候需要创建子进程去完成命令,为什么呢?
因为我们执行的一些命令可能会出现一些错误,子进程执行的话只会影响子进程的运行,不会影响到父进程。

6.1 函数介绍

fgets函数介绍
在这里插入图片描述
strtok函数介绍
在这里插入图片描述
chdir函数介绍
在这里插入图片描述

6.2 myshell.c完整代码

在这里插入图片描述

总结

以上就是进程控制全部的内容了,可以看到其中涉及到的知识点还是非常的多的,有的也不是很好理解,所以我们要多去看,多去总结,同时自己也要将这些函数全都用一下,这样才可以加深印象,如果文章中有错误的话,希望大家评论指出,我后面一定会改正,最后,如果你感觉我的文章对你有用的话,就给波三连吧!!谢谢大家

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/336918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux学习之操作系统认识

目录操作系统概念初识“管理”总结系统函数和库函数操作系统 概念 操作系统(英语:Operating System,缩写:OS)是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件…

了解并发编程

并发与并行的概念: 并发:一段时间内(假设只有一个CPU)执行多个线程,多个线程时按顺序执行 并行:同个时间点上,多个线程同时执行(多个CPU) 什么是并发编程? 在现代互联网的应用中,会出现多个请求同时对共享资源的访问情况,例如在买票,秒杀与抢购的场景中 此时就会出现线程安…

【排序算法】选择排序(Selection sort)

选择排序(Selection sort)是一种简单直观的排序算法。选择排序介绍它的基本思想是: 首先在未排序的数列中找到最小(or最大)元素,然后将其存放到数列的起始位置;接着,再从剩余未排序的元素中继续寻找最小(or最大)元素,然后放到已排…

c/c++开发,无可避免的宏定义使用案例

一、c/c宏定义的来源 宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。通常c/c宏定义这几处出处: 1)最常见的就是来自于开发者编码过程中采用宏定义命令“#…

发烧友实测 | 飞凌嵌入式OKA40i-C开发板试用体验之远程视频监控

本篇试用报告由发烧友zealsoft提供,感谢zealsoft的支持。飞凌嵌入式会在电子发烧友和电路城论坛持续开展开发板有奖试用活动,更有京东E卡等着你!欢迎大家的持续关注。“感谢飞凌嵌入式公司提供了本次OKA40i-C开发板的评测机会。上次我们介绍了…

网络流量传输MTU解析

基本概念 以太网的链路层对数据帧的长度会有一个限制,其最大值默认是1500字节,链路层的这个特性称为MTU,即最大传输单元 Maximum Transmission Unit,最大传输单元,指的是数据链路层的最大payload,由硬件网…

高压放大器在孔道灌浆非线性超声测试中的应用

实验名称:高压放大器在孔道灌浆非线性超声测试中的应用研究方向:无损检测测试目的:超声波作为频率高于20kHz的声波被广泛应用于各类结构的无损检测中,以超声波作为探伤波的无损检测法称为超声波无损检测法,简称超声波法…

嵌入式开发:通过嵌入式虚

嵌入式虚拟化为实现多核处理能力的优势提供了一种可扩展的机制。嵌入式应用中的虚拟化与其企业和桌面应用有许多共同之处。独特的嵌入式使用案例和专业的底层技术为嵌入式开发人员提供了优化性能和响应设计的新机会。在台式机、数据中心以及现在的嵌入式设计中采用多核技术可以…

React hooks之useState用法(一)

系列文章目录 学习React已经有很长的一段时间了,今天决定重新回顾一下跟React相关的一些知识点 文章目录系列文章目录结构如下一、hooks是什么?useState可以能做什么二、如何使用useState()第一步:创建【函数组件&…

java 代码

java 分层架构的由来目录概述需求:设计思路实现思路分析参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive. ha…

运维必会:ansible剧本(piaybook)

playbooks 概述以及实例操作 Playbooks 组成部分: Inventory Modules Ad Hoc Commands Playbooks Tasks: 任务,即调用模块完成的某些操作 Variables: 变量 Templates: 模板 Handlers: 处理器,由某时间触发执行的操作 Roles: 角色 YAML 介绍…

Individual Tree Segmentation from LiDAR Point Clouds for Urban Forest Inventory

Abstract 本研究的目的是使用 LiDAR 点云数据开发单棵树级别的自动化城市森林清单的新算法。激光雷达数据包含三维结构信息,可用于估算树高、基高、树冠深度和树冠直径。这使得精确的城市森林库存可以细化到单棵树。与大多数已发布的从 LiDAR 派生的栅格表面检测单…

学了这么久python,不会连自己啥python版本都不知道吧?

人生苦短,我用Python 源码资料电子书:点击此处跳转文末名片获取 查看 Python 版本 我们可以在命令窗口(Windows 使用 winR 调出 cmd 运行框)使用以下命令查看我们使用的 Python 版本: python -V 或 python --version 以上命令执行结果如下: …

Axure 初学者容易涉及的雷区

​工具学习是成为产品经理的一部分学习,工具学习总是伴随着痛苦和煎熬的,因为学习本身就伴随着枯燥和重复。 在未来你的Axure学习可能会出现这些情况呢?还没接触过axure的或者打算进行axure的朋友可能会有疑问。这里根据我们学员学习axure的经…

CentOS8基础篇4:使用U盘备份文件

一、挂载点 所谓的挂载点就是文件系统中存在的一个目录,通常情况下,创建在/mnt目录下,挂载成功后,访问挂载点就是访问新的存储设备。 挂载点应该是空目录,否则原来该挂载点中存在的文件将会被隐藏。而且,…

谷粒学苑第二章前端框架-2.1登录功能

一、vue-admin-template的config模块 vue-admin-template支持多环境,config配置模块提供了dev和prod两种环境。而BASE_API存储的是URL前部分,再拼接上controller的URL,即是完整的URL。修改为自己的协议://ip:port 二、vue-admin-template的s…

.net6API使用SignalR+vue3聊天+WPF聊天

目录 一、.net6api接口 二、vue3前端 三、WPF客户端 此案例分为3部分。首先创建.net6api接口,然后使用前端vue3进行聊天,再使用wpf客户端进行聊天,并且互通聊天。 一、.net6api接口 1.首先建立一个能正常运行的api,然后增加Ch…

redis未授权访问漏洞的三种场景复现以及加固思路

1.redis简介 redis是一个 非常快速 的,开源的,支持网络,可以基于内存,也可以持久化的日志型, 非关系型 的键值对数据库。并提供了多种语言的api。有java,c/c,c#,php,JavaScript,per…

1.Linux编程-gcc编译器

gcc的工作流程 gcc编译器将c源文件到生成一个可执行程序,中间一共经历了四个步骤: 四个步骤并不是gcc独立完成的,而是在内部调用了其他工具,从而完成了整个工作流程, 其中编译最耗时, 因为要逐行检查语法. gcc的工作流程: 1 预处理: cpp预处理器, 去掉注释, 展开头文件, …

Java进程CPU高负载排查步骤

近期发现服务器Java进程负载,超过100%一、采用top命令定位进程登录服务器,执行top命令,查看CPU占用情况,找到进程的pid很容易发现,PID为29706的java进程的CPU飙升到700%多,且一直降不下来,很显然…