2

I am trying to find an alternative to Java Runtime.exec() that does not use a fork. The problem being that our JVM consumes most of the memory and a Runtime.exec fork on that process may cause memory problems, even with copy on write and overcomit (which has been often discussed in stackoverflow, see Java Runtime.getRuntime().exec() alternatives).

On another stackoverflow post, a solution was suggested using JNA, yet there were no comments on this solution and it was not highly rated: How to solve "java.io.IOException: error=12, Cannot allocate memory" calling Runtime#exec()?

Likewise a similar JNA solution was suggested here: http://sanjitmohanty.wordpress.com/2011/12/20/overcoming-runtime-exec-havoc-with-jna/

My question is: does using JNA to make a system call prevent a fork, and does it avoid the subsequent memory allocation problems that fork can cause? Here is the code I am using:

public class TestJNA {
 private interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
    int system(String cmd);
 }
 private static int exec(String command) {
    return CLibrary.INSTANCE.system(command);
 }
 public static void main(String[] args) {
    exec("ls");
 }
Community
  • 1
  • 1
adamSpline
  • 483
  • 4
  • 13

4 Answers4

3

No. system is required to do a fork (or equivalent), and JNA can't do anything about that.

I don't think people are suggesting you use JNA to call system, but rather to do the actual system calls. For instance, that blog gives chmod and chown as examples. So, using your example, instead of using JNA to call system('ls'), call opendir and readdir (of course, the same applies to whatever you're really calling).

You may have to make a DLL to wrap the desired functionality.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
3

Probably not. The implementation of system() that you're calling is almost certainly using fork() itself -- the C implementation will look something like:

int system(const char *cmd) {
    if (fork() == 0) {
        execl("/bin/sh", "-c", cmd);
        _exit(1);
    }
    int result;
    wait(&result);
    return WEXITSTATUS(result);
}

A more feasible solution would be to maintain lines of communication (e.g, pipes) to a small external process which can spawn off subprocesses for you. Android does something very much like this; the external process is known as the "zygote".

  • thanks for the suggestion about using a small external process. I am using tcpserver from ucspi-tcp to listen for socket connections from Java. The tcpserver spawns off shell processes for me. Works like a charm and keeps my memory more predictable. – adamSpline May 24 '12 at 07:22
  • If you're using TCP, make sure that it's only accessible locally, and that it isn't exposed to processes of lower privilege levels. –  May 24 '12 at 14:48
1

There is no possibly way to execute the 'system' without a fork().

bmargulies
  • 97,814
  • 39
  • 186
  • 310
0

Then how system() does work? if it still using fork? i had a problem with this error "java.io.IOException: error=12, Cannot allocate memory" and this solved it for me:

private interface CLibrary extends Library {
            CLibrary INSTANCE = (CLibrary) Native.loadLibrary(("c"), CLibrary.class);
        int system(String cmd);
    }

    private static int exec(String command) {
        return CLibrary.INSTANCE.system(command);
    }
Gilo
  • 640
  • 3
  • 23