萌新最近搬砖遇到一个问题,上面让我做一个dump文件的自动解析系统,至于解析的工具,准备用的是google的breakpad,项目部署环境是linux+jdk1.8。其他的无关紧要也就不谈了。
一开始写了一个demo放到测试机上面跑,最初代码如下(只保留转换相关的代码,所以不可以运行):
import java.io.InputStreamReader;
public class DumpAnalyseUtil {
public static boolean analyseDumpFile(String stackPath, String dumpPath, String symPath, String logPath){
boolean result = false;
Process process = null;
File stackFile = new File(stackPath);
File dumpFile = new File(dumpPath);
File symbolFile = new File(symPath);
File logFile = new File(logPath);
try{
if (stackFile.exists() && dumpFile.exists() && symbolFile.exists()){
String command = stackPath + " " + dumpPath + " " + symPath + " > " + logPath;
System.out.println(command);
Runtime.getRuntime().exec(command).waitFor();
result = true;
}
}catch (Exception e){
System.out.println("Dump File Analysis Error: " + e.getMessage());
if (process != null){
try{
process.getErrorStream().close();
process.getInputStream().close();
process.getOutputStream().close();
}catch (IOException ie){
ie.printStackTrace();
}
}
}
return result;
}
public static void main(String[] args) {
String stackPath = "/data/breakpad/src/processor/minidump_stackwalk";
String dumpPath = "/data/dump/lalala.dmp";
String symPath = "/data/symbols/";
String logPath = "/data/symbols/123456.log";
boolean result = analyseDumpFile(stackPath, dumpPath, symPath, logPath);
System.out.println(result);
}
}
在测试环境中运行这个demo的时候,程序跑到waitFor()方法那里就卡住不动了。。。
后来发现是自己的java基础还是有些薄弱,java在执行runtime命令时,输入流和错误流都会不断地进入JVM的缓冲区(一般来说不会有输出流,但是如果我们的命令和java程序有信息交互的话,比如需要我们通过程序输入什么参数的时候,这时候也会产生一些输出流进入缓冲区,但是这些输出流应该很快就被读取了,所以出现阻塞一般都是输入流和错误流引起的)。如果我们不去将缓冲区的这些信息流读出来的话,他们就会一直待在缓冲区,并最终将其填满,造成runtime的阻塞。
知道了问题的所在,就好解决了。既然这些数据流不读取就会淤积的话,读出来就好了,于是有了改进第一版(只放了改进的那部分代码):
Process exec = Runtime.getRuntime().exec(command);
BufferedReader insertReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
exec.waitFor();
还有一种方式,就是如果这个错误输出流里面的信息对你来说没有什么价值的话,可以利用ProcessBuilder的redirectErrorStream方法,来把错误流和输入流整合到一起,一并读出来:
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
Process p = processBuilder.start();
InputStream is = p.getInputStream();
BufferedReader bs = new BufferedReader(new InputStreamReader(is));
另外,如果你的输入流信息非常多,比如拷贝文件的话,则可以单独起一个线程来读取输入流中的信息:
(这一块是参考了 望星辰大海 的博客中的代码 点击打开链接)
就不具体放出来了,有兴趣可以点击链接过去看一下。