当前位置:  开发笔记 > 编程语言 > 正文

Java Runtime.getRuntime().exec()替代方案

如何解决《JavaRuntime.getRuntime().exec()替代方案》经验,为你挑选了2个好方法。

我有一组在tomcat下运行的webapps.使用-Xmx参数将Tomcat配置为具有多达2 GB的内存.

许多Web应用程序需要执行最终使用以下代码的任务:

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);
process.waitFor();
...

我们遇到的问题与在Linux上创建这个"子进程"的方式有关(Redhat 4.4和Centos 5.4).

我的理解是,等于tomcat使用量的内存量需要在物理(非交换)系统内存池中自由,最初才能创建此子进程.当我们没有足够的免费物理内存时,我们得到了这个:

    java.io.IOException: error=12, Cannot allocate memory
     at java.lang.UNIXProcess.(UNIXProcess.java:148)
     at java.lang.ProcessImpl.start(ProcessImpl.java:65)
     at java.lang.ProcessBuilder.start(ProcessBuilder.java:452)
     ... 28 more

我的问题是:

1) 是否可以删除与物理内存中空闲进程相等的内存量的要求? 我正在寻找一个答案,允许我指定子进程获取多少内存或允许java上的java访问交换内存.

2) 如果没有#1的解决方案,Runtime.getRuntime().exec()有哪些替代方案? 我只能想到两个,这两个都不是很理想.JNI(非常不可取)或重写我们在java中调用的程序,并使其成为webapp以某种方式与之通信的自己的进程.必须有其他人.

3) 这个问题的另一面是否有可能解决这个问题? 降低tomcat使用的内存量不是一种选择.增加服务器上的内存总是一种选择,但似乎更像是一个创可贴.

服务器正在运行java 6.

编辑:我应该指定我不是在寻找特定于tomcat的修复程序.我们在网络服务器上运行的任何java应用程序都可以看到这个问题(有多个).我只是使用tomcat作为一个例子,因为它很可能会分配最多的内存,而这正是我们第一次看到错误的地方.这是一个可重现的错误.

编辑:最后,我们通过重写系统调用在java中执行的操作来解决此问题.我觉得我们很幸运能够在不进行额外系统调用的情况下完成此操作.并非所有流程都能够做到这一点,所以我仍然希望看到一个实际的解决方案.



1> luke..:

我在本文中找到了一种解决方法,基本上这个想法是你在应用程序启动时尽早创建一个进程(通过输入流)然后该子进程为你执行命令.

//you would probably want to make this a singleton
public class ProcessHelper
{
    private OutputStreamWriter output;
    public ProcessHelper()
    {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("java ProcessHelper");
        output = new OutputStreamWriter(process.getOutputStream());
    }
    public void exec(String command)
    {
        output.write(command, 0, command.length());
    }
}

然后你会做一个帮助java程序

public class ProcessHelper
{
    public static void main(String[] args)
    {
         BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
         String command;
         while((command = in.readLine()) != null)
         {
             Runtime runtime = Runtime.getRuntime();
             Process process = runtime.exec(command);
         }
    }
}

我们基本上做的是为你的应用程序制作一个'exec'服务器.如果您在应用程序的早期初始化ProcessHelper类,它将成功创建此过程,然后您只需将命令传递给它,因为第二个过程要小得多,它应该总是成功.

您还可以更深入地使用协议,例如返回exitcodes,通知错误等等.



2> Ian McLaird..:

尝试使用ProcessBuilder.Docs说这是现在启动子流程的"首选"方式.您还应该考虑使用环境贴图(文档在链接中)来指定新进程的内存容量.我怀疑(但不确定)它需要如此多内存的原因是它继承了tomcat进程的设置.使用环境贴图应该允许您覆盖该行为.但请注意,启动进程非常符合操作系统,因此YMMV.


据我所知,`ProcessBuilder`在Linux上受到相同的内存限制.
它需要如此大的内存的原因是,用于分离新进程的标准"fork"算法会导致执行进程暂时完全重复.据说这是启动子流程的唯一跨平台方式.据我所知,ProcessBuilder只提供了便利 - 它实际上并没有解决这个问题.
推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有