执行exec()没反应或卡住,主因是未处理子进程的输入/输出流,缓冲区满导致阻塞;必须显式读取或丢弃getinputstream()和geterrorstream()。

Runtime.getRuntime().exec() 执行命令为什么没反应或卡住
调用 exec() 后程序没报错、也没输出,甚至主线程卡死——大概率是没处理子进程的输入/输出流。Java 不会自动消费子进程的 stdout 和 stderr,缓冲区满后子进程就会阻塞(比如 ping 输出太多、ls -l 在管道场景下)。
- 必须显式读取
Process.getInputStream()和Process.getErrorStream(),哪怕只是丢弃:process.getInputStream().transferTo(new ByteArrayOutputStream());
- 别用
process.waitFor()前不读流,尤其在 Windows 上执行cmd /c dir类命令时极易卡死 - 推荐用
ProcessBuilder替代exec():它默认继承父进程的流(可设inheritIO()),也更容易控制工作目录和环境变量 - 注意路径分隔符:Windows 用
\或正斜杠/都行,但 Java 字符串里写"C:\Program Files"要双反斜杠;Linux 下避免硬编码/home/user,优先用System.getProperty("user.home")
getRuntime().freeMemory() / totalMemory() / maxMemory() 数值为什么和 top/jstat 差很多
这三个方法返回的是 JVM 堆内存的当前视图,不是操作系统级内存占用。它们只反映 GC 后堆的可用/已用/上限,完全不包含元空间、直接内存、线程栈、JIT 代码缓存等。
-
freeMemory()是“当前空闲堆”,不是“还能分配多少”——因为可能触发 GC 后才释放;它甚至可能比上次调用还大(GC 刚发生) -
maxMemory()默认等于-Xmx值,但如果没设-Xmx,它会随堆动态扩容,返回的是当前最大允许值,不是物理内存上限 - 想看真实内存占用?用
ManagementFactory.getOperatingSystemMXBean()获取getCommittedVirtualMemorySize()(JDK 8+)或解析/proc/self/status(Linux) - 监控场景下,别轮询
freeMemory()判断“内存是否紧张”——它波动剧烈,且和 OOM 无直接关系;应结合MemoryUsage从MemoryPoolMXBean获取各代使用率
Runtime.getRuntime().exit() 和 System.exit() 有什么区别
没区别。System.exit(int) 内部就是调用 Runtime.getRuntime().exit(int)。两者都会终止 JVM,触发 shutdown hooks,并返回退出码给操作系统。
- 不要在 Web 容器(Tomcat/Spring Boot)里调用它们:会杀死整个 JVM,不是只退出当前请求
- 退出码非 0(如
exit(1))表示异常终止,Shell 脚本里可用$?检查;但 Java 程序中,除非是脚本启动的独立工具类应用,否则基本不该主动 exit - 如果想“退出当前逻辑”而非整个 JVM,用
return、抛业务异常、或明确 break/continue,而不是exit() - shutdown hook 里禁止再调用
exit(),会导致死锁——JVM 正在执行 hook 时已禁用新 hook 注册和 exit 调用
Runtime 类为什么不能直接 new,且 getRuntime() 总是返回同一个实例
因为 Runtime 是单例,构造函数私有,且 JVM 在启动时就创建了唯一实例。这是早期 Java 的典型饿汉式单例,不是靠 synchronized 或双重检查实现的,而是由 JVM 硬编码保证。
立即学习“Java免费学习笔记(深入)”;
- 调用多次
Runtime.getRuntime()返回的确实是同一对象,== 比较结果为 true;但别拿它做全局状态容器——没有线程安全保证,也没有 clear/reset 方法 - 不能
new Runtime():编译直接报错,构造函数是private Runtime() - 这个单例不参与任何类加载器隔离:即使在不同 ClassLoader 加载的代码里调用
getRuntime(),拿到的仍是 VM 级单例,共享所有状态(比如 shutdown hooks 是全局注册的) - 现代代码中,真正需要直接操作 Runtime 的场景极少;执行命令优先用
ProcessBuilder,内存监控优先走 MXBean,退出逻辑尽量避免 exit —— Runtime 类本身,就是个被时代部分架空的遗留接口










