linux定时结束java进程_使用zt-exec库定时清理linux休眠进程
在幾個月前上線的一個采集項目,構架是基于java + selenium + chromedriver + chrome實現的采集。至于為哈不直接用jsoup或httpclient實現采集功能,是因為很多被采集頁面都是通過js來渲染內容的,所以必須用webdriver+chrome來模擬真正的瀏覽器訪問來采集。
每隔一段時間就會出采集失敗問題,出現的時間沒有規律,可能兩天出現一次,可能一星期出現一次,可能一個月出現一次....
用linux top命令來查看服務器,會發現很多的chromedriver和chrome的進程
用ps命令查看服務器
ps -aux | grep chrome
存在狀態為Sl和Z的休眠進程和僵尸進程,啟動時間都不是當天,根據系統本身業務邏輯,進程不會存在運行那么長時間的情況。而java進程則全部都能正常關閉,但java進程啟動的chromedriver和chrome進程不一定能同時關閉,目前出現這種問題的原因未找到。
最初想用命令把卡死的進程查出來批量殺掉
ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9 //殺死僵尸進程
結果發現只能查殺Z狀態的僵尸進程,Sl狀態的進程,一部分是正常的,一部分是需要殺死的(啟動時間為Nov07,Nov06的進程需要殺掉),至于哪些需要殺死,需要通過人工判斷啟動時間來確定是否需要殺掉進程。
之前一直忙時,都是先通過ps命令把chromedriver和chrome相關進程查詢出來,然后通過人工判斷進程是否屬于休眠狀態,再手工kill殺掉進程。
最近有空了,本著能程序解決,就絕不要人工維護,把之前的手工殺休眠進程操作程序化。一開始想直接通過java的Runtime.getRuntime().exec()代碼調用linux命令操作的,不過在java常用類庫中(https://www.21doc.net/java/awesomejava#processes),找到zt-exec庫,可以簡化命令行調用操作。
程序化的代替人工維護實現定時清理休眠進程代碼如下:
import org.apache.log4j.Logger;
import org.apache.log4j.RollingFileAppender;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.stream.LogOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ProcessKill {
private static Logger log = Logger.getLogger(ProcessKill.class);
public ProcessKill(){
}
public void run(){
try{
List> list = new ArrayList>();
// 先通過ps aux | grep chrome命令,獲取所有包含chrome文本內容的進程
new ProcessExecutor().command("/bin/sh","-c","ps aux | grep chrome")
.redirectOutput(new LogOutputStream() {
protected void processLine(String line) {
log.info("line========" + line);
List lines = split(line.trim());
// 判斷進程啟動時間,確定是否為執行超時休眠的進程
String time = lines.get(8);
String format = "[0-5][0-9]:[0-5][0-9]";
Pattern p = Pattern.compile(format);
Matcher m = p.matcher(time);
boolean result = m.find();
if(result == true) {
log.info("time ========" + time + " " + result);
}
else{
log.info("time xxxxxxxx" + time + " " + result);
list.add(lines);
}
}
})
.execute();
log.info("list========size:" + list.size());
list.forEach(l->{
log.info("list line========" + l);
});
for(int i = 0; i < list.size(); i++){
List strs = list.get(i);
try{
String pid = strs.get(1);
String stat = strs.get(7);
String time = strs.get(8);
String cmd = strs.get(10);
log.info("pid========" + pid + ", " + stat + ", " + time + ", " + cmd);
// 通過命令“kill -9 pid”殺掉進程
String output = new ProcessExecutor().command("/bin/sh","-c","kill -9 " + pid)
.readOutput(true).execute()
.outputUTF8();
log.info("kill========" + pid + ", " + output);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
catch(Exception e){
e.printStackTrace();
}
}
public List split(String s){
// ps aux | grep chrome 命令返回字段: USER,PID ,%CPU,%MEM,VSZ, RSS,TTY,STAT,START,TIME,COMMAND
List list = new ArrayList();
int blankCount = 0;
StringBuffer sff = new StringBuffer();
for(int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if(list.size() < 10){
if(c != ' '){
sff.append(c);
blankCount = 0;
}
else if(c == ' '){
blankCount++;
}
if(blankCount == 1){
list.add(sff.toString());
sff = new StringBuffer();
}
}
else{
sff.append(c);
}
}
if(sff.length() > 0){
list.add(sff.toString());
}
return list;
}
public static void setLogFile(String name){
Logger rootLogger = Logger.getRootLogger();
Enumeration en = rootLogger.getAllAppenders();
while (en.hasMoreElements()){
Object obj = en.nextElement();
if(obj instanceof RollingFileAppender){
RollingFileAppender file = (RollingFileAppender)obj;
file.setFile(name + ".log");
file.activateOptions();
}
}
}
public static void main(String[] args){
setLogFile("log/" + ProcessKill.class.getSimpleName());
new ProcessKill().run();
}
}
文末記錄下ps和grep命令用法。
ps 顯示瞬間進程的狀態
參數:
-A :所有的進程均顯示出來,與 -e 具有同樣的效用;
-a : 顯示現行終端機下的所有進程,包括其他用戶的進程;
-u :以用戶為主的進程狀態 ;
x :通常與 a 這個參數一起使用,可列出較完整信息。
ps aux
USER:該進程屬于那個使用者賬號。
PID :該進程的進程ID號。
%CPU:該進程使用掉的 CPU 資源百分比;
%MEM:該進程所占用的物理內存百分比;
VSZ :該進程使用掉的虛擬內存量 (Kbytes)
RSS :該進程占用的固定的內存量 (Kbytes)
TTY :該進程是在那個終端機上面運作,若與終端機無關,則顯示。另外, tty1-tty6 是本機上面的登入者程序,若為 pts/0 等等的,則表示為由網絡連接進主機的程序。
STAT:該程序目前的狀態,主要的狀態有:
R :該程序目前正在運作,或者是可被運作;
S :該程序目前正在睡眠當中,但可被某些訊號(signal) 喚醒。
T :該程序目前正在偵測或者是停止了;
Z :該程序應該已經終止,但是其父程序卻無法正常的終止他,造成 zombie (疆尸) 程序的狀態
START:該進程被觸發啟動的時間;
TIME :該進程實際使用 CPU 運作的時間。
COMMAND:該程序的實際指令。
ps -ef |grep java
UID :程序被該 UID 所擁有
PID :就是這個程序的 ID
PPID :則是其上級父程序的ID
C :CPU使用的資源百分比
STIME :系統啟動時間
TTY :登入者的終端機位置
TIME :使用掉的CPU時間。
CMD :所下達的是什么指令
grep命令的常用格式為:grep ?[選項] ?”模式“ ?[文件]
常用選項:
-E :開啟擴展(Extend)的正則表達式。
-i :忽略大小寫(ignore case)。
-v :反過來(invert),只打印沒有匹配的,而匹配的反而不打印。
-n :顯示行號
-w :被匹配的文本只能是單詞,而不能是單詞中的某一部分,如文本中有liker,而我搜尋的只是like,就可以使用-w選項來避免匹配liker
-c :顯示總共有多少行被匹配到了,而不是顯示被匹配到的內容,注意如果同時使用-cv選項是顯示有多少行沒有被匹配到。
-o :只顯示被模式匹配到的字符串。
--color :將匹配到的內容以顏色高亮顯示。
-A n:顯示匹配到的字符串所在的行及其后n行,after
-B n:顯示匹配到的字符串所在的行及其前n行,before
-C n:顯示匹配到的字符串所在的行及其前后各n行,context
查看系統狀態下的僵尸進程:
ps -ef | grep defunct ?后面尖括號里是defunct的都是僵尸進程。
ps aux | grep -w 'Z' 其中狀態為Z的代表僵尸進程。
總結
以上是生活随笔為你收集整理的linux定时结束java进程_使用zt-exec库定时清理linux休眠进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: token拦截器android_vue.
- 下一篇: python中文件打开的合法模式组合_详