【问题标题】:Does JNA system() avoid a forkJNA system() 是否避免分叉
【发布时间】:2012-05-24 00:21:13
【问题描述】:

我正在尝试寻找不使用 fork 的 Java Runtime.exec() 替代方案。问题是我们的 JVM 消耗了大部分内存,并且该进程上的 Runtime.exec 分叉可能会导致内存问题,即使在写入时复制和过度使用时也是如此(这在 stackoverflow 中经常讨论,请参阅Java Runtime.getRuntime().exec() alternatives)。

在另一个 stackoverflow 帖子中,提出了使用 JNA 的解决方案,但该解决方案上没有 cmets,并且评价不高:How to solve "java.io.IOException: error=12, Cannot allocate memory" calling Runtime#exec()?

这里也建议了类似的 JNA 解决方案:http://sanjitmohanty.wordpress.com/2011/12/20/overcoming-runtime-exec-havoc-with-jna/

我的问题是:使用 JNA 进行系统调用是否会阻止分叉,是否避免了分叉可能导致的后续内存分配问题?这是我正在使用的代码:

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

【问题讨论】:

    标签: java runtime exec jna


    【解决方案1】:

    可能不会。您调用的system() 的实现几乎可以肯定是使用fork() 本身——C 实现看起来像:

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

    一个更可行的解决方案是保持与一个小型外部进程的通信线路(例如管道),该进程可以为您生成子进程。 Android 做了很多类似的事情;外部进程被称为“zygote”。

    【讨论】:

    • 感谢有关使用小型外部进程的建议。我正在使用来自 ucspi-tcp 的 tcpserver 来监听来自 Java 的套接字连接。 tcpserver 为我生成了 shell 进程。就像一个魅力,让我的记忆更容易预测。
    • 如果您使用 TCP,请确保它只能在本地访问,并且不会暴露给较低权限级别的进程。
    【解决方案2】:

    没有。 systemfork (或等效项)所必需的,而 JNA 对此无能为力。

    我不认为人们建议您使用 JNA 调用 system,而是进行实际的系统调用。例如,该博客以chmodchown 为例。因此,使用您的示例,而不是使用 JNA 调用 system('ls'),而是调用 opendirreaddir(当然,这同样适用于您真正调用的任何内容)。

    您可能必须创建一个 DLL 来包装所需的功能。

    【讨论】:

      【解决方案3】:

      没有 fork() 就不可能执行“系统”。

      【讨论】:

        【解决方案4】:

        那么 system() 是如何工作的呢?如果它还在使用叉子? 我遇到了这个错误“java.io.IOException:错误= 12,无法分配内存”的问题 这为我解决了这个问题:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-10-13
          • 2020-08-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多