Java Runtime.getRuntime().exec() alternatives

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

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

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.


Try using a ProcessBuilder. The Docs say that's the "preferred" way to start up a sub-process these days. You should also consider using the environment map (docs are in the link) to specify the memory allowances for the new process. I suspect (but don't know for certain) that the reason it needs so much memory is that it is inheriting the settings from the tomcat process. Using the environment map should allow you to override that behavior. However, note that starting up a process is very OS specific, so YMMV.


I think this is a unix fork() issue, the memory requirement comes from they way fork() works -- it first clones the child process image (at whatever size it currently is) then replaces the parent image with the child image. I know on Solaris there is some way to control this behavior, but I don't know offhand what it is.

Update: This is already explained in From what Linux kernel/libc version is Java Runtime.exec() safe with regards to memory?


This would help I think. I know this is an old thread, just for future refs... http://wrapper.tanukisoftware.com/doc/english/child-exec.html


Another alternative is to have a separate exec process running that watches either a file or some other type of "queue". You append your desired command to that file, and the exec server spots it, running the command, and somehow writing the results to another location you can get.