Skip to content

Commit

Permalink
添加一个kill chrome示例和linux僵尸进程解决方案
Browse files Browse the repository at this point in the history
  • Loading branch information
fanyong920 committed Jun 18, 2024
1 parent 6b8855c commit ea61d2b
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 10 deletions.
207 changes: 207 additions & 0 deletions 1.1.5版本之前的内存问题解决方案.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
## step 1 导入jna包
```xml
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>
```
## step 2 创建内部接口
```java
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
long GetProcessId(Long hProcess);
}
```

## step 3 写获取进程id的方法

````java
/**
* 获取进程id
* @param process chrome进程 可以通过{@link com.ruiyun.jvppeteer.core.browser.Browser#process()} 获取}
* @return 进程id
*/
public static String getProcessId(Process process) {
long pid = -1;
Field field;
if (Platform.isWindows()) {
try {
field = process.getClass().getDeclaredField("handle");
field.setAccessible(true);
pid = BrowserRunner.Kernel32.INSTANCE.GetProcessId((Long) field.get(process));
} catch (Exception e) {
LOGGER.error("Failed to get processId on Windows platform.",e);
}
} else if (Platform.isLinux() || Platform.isAIX()) {
try {
String version = System.getProperty("java.version");
double jdkversion = Double.parseDouble(version.substring(0, 3));
Class<?> clazz;
//如果生产环境是jdk8,就不用if判断了
if (jdkversion <= 1.8) {
clazz = Class.forName("java.lang.UNIXProcess");
} else {
clazz = Class.forName("java.lang.ProcessImpl");
}
field = clazz.getDeclaredField("pid");
field.setAccessible(true);
pid = (Integer) field.get(process);
} catch (Throwable e) {
LOGGER.error("Failed to get processId on Linux or Aix platform.",e);
}
}
return String.valueOf(pid);
}
````
## step 4 通过kill 命令杀死进程

````java
/**
* kill 掉浏览器进程
*/
public boolean kill() {
try {
String pid = pidMap.get(this.process);
if("-1".equals(pid)){
LOGGER.warn("Chrome process pid is -1,will not use kill cmd");
return false;
}
if(StringUtil.isEmpty(pid) ){
LOGGER.warn("Chrome process pid is empty,will not use kill cmd");
return false;
}
Process exec = null;
String command = "";
if (Platform.isWindows()) {
command = "cmd.exe /c taskkill /PID " + pid + " /F /T ";
} else if (Platform.isLinux() || Platform.isAIX()) {
command = "kill -9 " + pid;
}
LOGGER.info("kill chrome process by pid,command: kill -9 {}", pid);
exec = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",command});
return exec.waitFor(Constant.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
LOGGER.error("kill chrome process error ", e);
return false;
}
}
````
## 完整代码示例
````java

package com.ruiyun.example;

import com.ruiyun.jvppeteer.core.Constant;
import com.ruiyun.jvppeteer.core.Puppeteer;
import com.ruiyun.jvppeteer.core.browser.Browser;
import com.ruiyun.jvppeteer.core.browser.BrowserRunner;
import com.ruiyun.jvppeteer.core.page.Page;
import com.ruiyun.jvppeteer.options.LaunchOptions;
import com.ruiyun.jvppeteer.options.LaunchOptionsBuilder;
import com.ruiyun.jvppeteer.util.StringUtil;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class KillExample {

private static final Logger LOGGER = LoggerFactory.getLogger(BrowserRunner.class);
/**
* 多个browser的时候用pids储存pid
*/
private static Map<String,Process> pids = new HashMap<>();
public static void main(String[] args) throws IOException, InterruptedException {
LaunchOptions launchOptions = new LaunchOptionsBuilder().withExecutablePath("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe").withIgnoreDefaultArgs(Collections.singletonList("--enable-automation")).withHeadless(false).build();
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.baidu.com/?tn=98012088_10_dg&ch=3");
Process process = browser.process();
String processId = getProcessId(process);
KillExample.LOGGER.info("process pid {}",processId);
// 做一些其他操作


browser.close(); //可以关闭websocket连接
kill(processId);
}

public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
long GetProcessId(Long hProcess);
}

public static String getProcessId(Process process) {
long pid = -1;
Field field;
if (Platform.isWindows()) {
try {
field = process.getClass().getDeclaredField("handle");
field.setAccessible(true);
pid = KillExample.Kernel32.INSTANCE.GetProcessId((Long) field.get(process));
} catch (Exception e) {
KillExample.LOGGER.error("Failed to get processId on Windows platform.",e);
}
} else if (Platform.isLinux() || Platform.isAIX()) {
try {
String version = System.getProperty("java.version");
double jdkversion = Double.parseDouble(version.substring(0, 3));
Class<?> clazz;
//如果生产环境是jdk8,就不用if判断了
if (jdkversion <= 1.8) {
clazz = Class.forName("java.lang.UNIXProcess");
} else {
clazz = Class.forName("java.lang.ProcessImpl");
}
field = clazz.getDeclaredField("pid");
field.setAccessible(true);
pid = (Integer) field.get(process);
} catch (Throwable e) {
KillExample.LOGGER.error("Failed to get processId on Linux or Aix platform.",e);
}
}
return String.valueOf(pid);
}

public static boolean kill(String pid) {
try {
if("-1".equals(pid)){
LOGGER.warn("Chrome process pid is -1,will not use kill cmd");
return false;
}
if(StringUtil.isEmpty(pid) ){
LOGGER.warn("Chrome process pid is empty,will not use kill cmd");
return false;
}
Process exec = null;
String command = "";
if (Platform.isWindows()) {
command = "cmd.exe /c taskkill /PID " + pid + " /F /T ";
exec = Runtime.getRuntime().exec(command);
} else if (Platform.isLinux() || Platform.isAIX()) {
command = "kill -9 " + pid;
exec = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",command});
}
if (exec != null) {
return exec.waitFor(Constant.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
LOGGER.error("kill chrome process error ", e);
return false;
}
return false;
}
}

````


109 changes: 109 additions & 0 deletions example/src/main/java/com/ruiyun/example/KillExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.ruiyun.example;

import com.ruiyun.jvppeteer.core.Constant;
import com.ruiyun.jvppeteer.core.Puppeteer;
import com.ruiyun.jvppeteer.core.browser.Browser;
import com.ruiyun.jvppeteer.core.browser.BrowserRunner;
import com.ruiyun.jvppeteer.core.page.Page;
import com.ruiyun.jvppeteer.options.LaunchOptions;
import com.ruiyun.jvppeteer.options.LaunchOptionsBuilder;
import com.ruiyun.jvppeteer.util.StringUtil;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class KillExample {

private static final Logger LOGGER = LoggerFactory.getLogger(BrowserRunner.class);
/**
* 多个browser的时候用pids储存pid
*/
private static Map<String,Process> pids = new HashMap<>();
public static void main(String[] args) throws IOException, InterruptedException {
LaunchOptions launchOptions = new LaunchOptionsBuilder().withExecutablePath("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe").withIgnoreDefaultArgs(Collections.singletonList("--enable-automation")).withHeadless(false).build();
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.baidu.com/?tn=98012088_10_dg&ch=3");
Process process = browser.process();
String processId = getProcessId(process);
KillExample.LOGGER.info("process pid {}",processId);
kill(processId);
// 做一些其他操作
browser.close();
}

public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
long GetProcessId(Long hProcess);
}

public static String getProcessId(Process process) {
long pid = -1;
Field field;
if (Platform.isWindows()) {
try {
field = process.getClass().getDeclaredField("handle");
field.setAccessible(true);
pid = KillExample.Kernel32.INSTANCE.GetProcessId((Long) field.get(process));
} catch (Exception e) {
KillExample.LOGGER.error("Failed to get processId on Windows platform.",e);
}
} else if (Platform.isLinux() || Platform.isAIX()) {
try {
String version = System.getProperty("java.version");
double jdkversion = Double.parseDouble(version.substring(0, 3));
Class<?> clazz;
//如果生产环境是jdk8,就不用if判断了
if (jdkversion <= 1.8) {
clazz = Class.forName("java.lang.UNIXProcess");
} else {
clazz = Class.forName("java.lang.ProcessImpl");
}
field = clazz.getDeclaredField("pid");
field.setAccessible(true);
pid = (Integer) field.get(process);
} catch (Throwable e) {
KillExample.LOGGER.error("Failed to get processId on Linux or Aix platform.",e);
}
}
return String.valueOf(pid);
}

public static boolean kill(String pid) {
try {
if("-1".equals(pid)){
LOGGER.warn("Chrome process pid is -1,will not use kill cmd");
return false;
}
if(StringUtil.isEmpty(pid) ){
LOGGER.warn("Chrome process pid is empty,will not use kill cmd");
return false;
}
Process exec = null;
String command = "";
if (Platform.isWindows()) {
command = "cmd.exe /c taskkill /PID " + pid + " /F /T ";
exec = Runtime.getRuntime().exec(command);
} else if (Platform.isLinux() || Platform.isAIX()) {
command = "kill -9 " + pid;
exec = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",command});
}
if (exec != null) {
return exec.waitFor(Constant.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
LOGGER.error("kill chrome process error ", e);
return false;
}
return false;
}
}
7 changes: 1 addition & 6 deletions src/main/java/com/ruiyun/jvppeteer/core/Puppeteer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
import com.ruiyun.jvppeteer.launch.ChromeLauncher;
import com.ruiyun.jvppeteer.launch.FirefoxLauncher;
import com.ruiyun.jvppeteer.launch.Launcher;
import com.ruiyun.jvppeteer.options.BrowserOptions;
import com.ruiyun.jvppeteer.options.ChromeArgOptions;
import com.ruiyun.jvppeteer.options.FetcherOptions;
import com.ruiyun.jvppeteer.options.LaunchOptions;
import com.ruiyun.jvppeteer.options.LaunchOptionsBuilder;
import com.ruiyun.jvppeteer.options.*;
import com.ruiyun.jvppeteer.transport.ConnectionTransport;
import com.ruiyun.jvppeteer.util.StringUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static com.ruiyun.jvppeteer.core.Constant.PRODUCT_ENV;
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/com/ruiyun/jvppeteer/core/browser/BrowserRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ public void onBrowserEvent(Object event) {
* kill 掉浏览器进程
*/
public boolean kill() {
if(this.closed){
return true;
}
try {
String pid = pidMap.get(this.process);
if("-1".equals(pid)){
Expand All @@ -231,13 +234,16 @@ public boolean kill() {
String command = "";
if (Platform.isWindows()) {
command = "cmd.exe /c taskkill /PID " + pid + " /F /T ";
exec = Runtime.getRuntime().exec(command);
} else if (Platform.isLinux() || Platform.isAIX()) {
command = "kill -9 " + pid;
exec = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",command});
}
try {
LOGGER.info("kill chrome process by pid,command: kill -9 {}", pid);
exec = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",command});
return exec.waitFor(Constant.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
if (exec != null) {
LOGGER.info("kill chrome process by pid,command: {}", command);
return exec.waitFor(Constant.DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
} finally {
this.destroyCmdProcess(exec,command);
if (StringUtil.isNotEmpty(this.tempDirectory)) {
Expand All @@ -248,6 +254,7 @@ public boolean kill() {
LOGGER.error("kill chrome process error ", e);
return false;
}
return false;
}


Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/ruiyun/jvppeteer/util/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,6 @@ public static String getProcessId(Process process) {
try {
String version = System.getProperty("java.version");
double jdkversion = Double.parseDouble(version.substring(0, 3));
System.out.println("jdkversion = " +jdkversion);
Class<?> clazz;
if (jdkversion <= 1.8) {
clazz = Class.forName("java.lang.UNIXProcess");
Expand Down

0 comments on commit ea61d2b

Please sign in to comment.