Java Runtime.getRuntime().exec() 替代方案 [英] Java Runtime.getRuntime().exec() alternatives

查看:128
本文介绍了Java Runtime.getRuntime().exec() 替代方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a collection of webapps that are running under tomcat. Tomcat is configured to have as much as 2 GB of memory using the -Xmx argument.

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

Many of the webapps need to perform a task that ends up making use of the following code:

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

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

The issue we are having is related to the way that this "child-process" is getting created on Linux (Redhat 4.4 and Centos 5.4).

我的理解是,为了创建这个子进程,最初需要在物理(非交换)系统内存池中释放与 tomcat 使用量相等的内存量.当我们没有足够的可用物理内存时,我们会得到这个:

It's my understanding that an amount of memory equal to the amount tomcat is using needs to be free in the pool of physical (non-swap) system memory initially for this child process to be created. When we don't have enough free physical memory, we are getting this:

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

我的问题是:

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

1) Is it possible to remove the requirement for an amount of memory equal to the parent process being free in the physical memory? I'm looking for an answer that allows me to specify how much memory the child process gets or to allow java on linux to access swap memory.

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

2) What are the alternatives to Runtime.getRuntime().exec() if no solution to #1 exists? I could only think of two, neither of which is very desirable. JNI (very un-desirable) or rewriting the program we are calling in java and making it it's own process that the webapp communicates with somehow. There has to be others.

3) 这个问题还有其他方面我没有看到可以解决吗? 降低 tomcat 使用的内存量不是一个选项.增加服务器上的内存始终是一种选择,但似乎更像是一种创可贴.

3) Is there another side to this problem that I'm not seeing that could potentially fix it? Lowering the amount of memory used by tomcat is not an option. Increasing the memory on the server is always an option, but seems like more a band-aid.

服务器正在运行 Java 6.

Servers are running java 6.

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

I should specify that I'm not looking for a tomcat specific fix. This problem can be seen with any of the java applications we have running on the webserver (there are multiple). I simply used tomcat as an example because it will most likely have the most memory allocated to it and it's where we actually saw the error the first time. It is a reproducible error.

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

In the end, we solved this problem by re-writing what the system call was doing in java. I feel that we were pretty lucky being able to do this without making additional system calls. Not all processes will be able to do this, so I would still love to see an actual solution to this.

推荐答案

我在这个 文章,基本上这个想法是你在你的应用程序启动的早期创建一个进程,你与之通信(通过输入流)然后该子进程为你执行你的命令.

I found a workaround in this article, basically the idea is that you create a process early on in the startup of your application that you communicate with (via input streams) and then that subprocess executes your commands for you.

//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程序

then you would make a helper java program

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);
         }
    }
}

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

what we've essentially done is make a little 'exec' server for your application. If you initialize your ProcessHelper class early on in your application it will successfully create this process then you simply pipe commands over to it, because the second process is much smaller it should always succeed.

您还可以使您的协议更深入一些,例如返回退出代码、通知错误等.

You could also make your protocol a little more in depth, such as returning exitcodes, notifying of errors and so on.

这篇关于Java Runtime.getRuntime().exec() 替代方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆