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

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

问题描述

我有一组在tomcat下运行的webapps。使用-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.

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

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();
...

我们遇到的问题与这个孩子的方式有关-process正在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)是否有可能删除内存量等于父进程在物理内存中空闲的要求?我正在寻找一个答案,允许我指定子进程获取多少内存或允许java上的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);
         }
    }
}

我们基本上做了什么是为您的应用程序制作一个'exec'服务器。如果您在应用程序的早期初始化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.

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

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天全站免登陆