ProcessBuilder调用javac正常 运行目标程序返回-1073741819
问题说明
Java开发中使用ProcessBuilder调用外部程序时出现异常:调用javac.exe可正常执行,但调用目标程序pdf24-Ocr.exe时进程无法正常运行,返回退出码-1073741819,原实现代码如下:
ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "\"C:\\Program Files\\PDF24\\pdf24-Ocr.exe\"", "-outputFile", "C:\\ocr\\06062022120232-0001_color300_ocred2.pdf", "C:\\OCR\\06062022120232-0001_color300.pdf"); ///// ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "\"C:\\Program Files\\Java\\jdk-18.0.1.1\\bin\\javac.exe\"", "--help"); builder.redirectErrorStream(true); final Process process = builder.start(); // Watch the process /////watch(process); BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; try { while ((line = input.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } /////process.waitFor(30, TimeUnit.MINUTES); ///// System.out.println("before wait for ..."); int exitCode = process.waitFor(); System.out.println("\nExited Code : "+exitCode);
根因分析
退出码-1073741819对应Windows系统原生错误码0xC0000005 (STATUS_ACCESS_VIOLATION),即内存访问违规,当前场景触发该错误的核心原因有两个:
- 多余的
cmd /c包装:ProcessBuilder原生支持直接调用exe路径,额外套一层cmd启动会导致子进程继承错误的控制台句柄、桌面会话上下文。pdf24-Ocr.exe不是纯无界面命令行程序,底层依赖GUI组件资源,启动时获取不到合法上下文就会直接触发内存崩溃;而测试用的javac.exe是纯命令行程序,不依赖GUI相关资源,所以套cmd启动也能正常运行。 - IO处理逻辑缺陷:在主线程同步读取进程输出流,没有重定向标准输入,也没有做流读取的异步处理。GUI类程序启动时如果尝试绑定父进程IO句柄失败、或者输出流缓冲区写满被阻塞,也会触发进程异常退出。另外手动给exe路径加了双引号,
ProcessBuilder会自动处理带空格的路径,手动加引号反而会导致参数解析错误。
修复方案
按以下两点调整代码即可:
- 移除
cmd /c包装,直接把exe完整路径作为第一个命令参数,不要手动给路径加双引号。 - 重定向子进程标准输入到Windows空设备
NUL:,异步读取输出流避免缓冲区阻塞,保留超时机制防止进程无限挂起。
修复后可直接运行的代码如下:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.File; import java.util.concurrent.TimeUnit; public class Pdf24OcrTest { public static void main(String[] args) throws IOException, InterruptedException { // 直接调用exe,无需cmd中转,无需手动给路径加引号 ProcessBuilder builder = new ProcessBuilder( "C:\\Program Files\\PDF24\\pdf24-Ocr.exe", "-outputFile", "C:\\ocr\\06062022120232-0001_color300_ocred2.pdf", "C:\\OCR\\06062022120232-0001_color300.pdf" ); builder.redirectErrorStream(true); // 重定向标准输入到空设备,避免程序读取输入时卡住 builder.redirectInput(ProcessBuilder.Redirect.from(new File("NUL:"))); Process process = builder.start(); // 异步线程读取输出流,避免缓冲区满阻塞进程 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } }).start(); System.out.println("before wait for ..."); // 加超时控制,避免进程异常挂死 boolean isFinished = process.waitFor(30, TimeUnit.MINUTES); if (!isFinished) { process.destroyForcibly(); throw new RuntimeException("OCR process execute timeout"); } int exitCode = process.exitValue(); System.out.println("\nExited Code : " + exitCode); } }
注意事项
如果调整后依然报错,先直接在系统cmd窗口手动拼完整命令执行,确认命令本身参数正确、程序可正常运行,再放到Java代码中调用。
- 所有通过
ProcessBuilder调用Windows平台带界面的程序时,都尽量不要用cmd /c中转,直接调用exe路径即可。 - 不要手动给命令参数包裹双引号,
ProcessBuilder会自动处理路径中的空格,手动加引号会导致系统把引号识别为路径的一部分,触发文件找不到、参数解析错误等问题。
内容的提问来源于stack exchange,提问作者andrew wong
相关产品推荐
相关产品推荐

