我有一组在tomcat下运行的webapps.使用-Xmx参数将Tomcat配置为具有多达2 GB的内存.
许多Web应用程序需要执行最终使用以下代码的任务:
Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command); process.waitFor(); ...
我们遇到的问题与在Linux上创建这个"子进程"的方式有关(Redhat 4.4和Centos 5.4).
我的理解是,等于tomcat使用量的内存量需要在物理(非交换)系统内存池中自由,最初才能创建此子进程.当我们没有足够的免费物理内存时,我们得到了这个:
java.io.IOException: error=12, Cannot allocate memory at java.lang.UNIXProcess.(UNIXProcess.java:148) at java.lang.ProcessImpl.start(ProcessImpl.java:65) at java.lang.ProcessBuilder.start(ProcessBuilder.java:452) ... 28 more
我的问题是:
1) 是否可以删除与物理内存中空闲进程相等的内存量的要求? 我正在寻找一个答案,允许我指定子进程获取多少内存或允许java上的java访问交换内存.
2) 如果没有#1的解决方案,Runtime.getRuntime().exec()有哪些替代方案? 我只能想到两个,这两个都不是很理想.JNI(非常不可取)或重写我们在java中调用的程序,并使其成为webapp以某种方式与之通信的自己的进程.必须有其他人.
3) 这个问题的另一面是否有可能解决这个问题? 降低tomcat使用的内存量不是一种选择.增加服务器上的内存总是一种选择,但似乎更像是一个创可贴.
服务器正在运行java 6.
编辑:我应该指定我不是在寻找特定于tomcat的修复程序.我们在网络服务器上运行的任何java应用程序都可以看到这个问题(有多个).我只是使用tomcat作为一个例子,因为它很可能会分配最多的内存,而这正是我们第一次看到错误的地方.这是一个可重现的错误.
编辑:最后,我们通过重写系统调用在java中执行的操作来解决此问题.我觉得我们很幸运能够在不进行额外系统调用的情况下完成此操作.并非所有流程都能够做到这一点,所以我仍然希望看到一个实际的解决方案.
我在本文中找到了一种解决方法,基本上这个想法是你在应用程序启动时尽早创建一个进程(通过输入流)然后该子进程为你执行命令.
//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程序
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类,它将成功创建此过程,然后您只需将命令传递给它,因为第二个过程要小得多,它应该总是成功.
您还可以更深入地使用协议,例如返回exitcodes,通知错误等等.
尝试使用ProcessBuilder.Docs说这是现在启动子流程的"首选"方式.您还应该考虑使用环境贴图(文档在链接中)来指定新进程的内存容量.我怀疑(但不确定)它需要如此多内存的原因是它继承了tomcat进程的设置.使用环境贴图应该允许您覆盖该行为.但请注意,启动进程非常符合操作系统,因此YMMV.