Exception Trace:
In the Linux circumstance, when the program executes till this place:
Process p = Runtime.getRuntime().exec(cmdArr);
it throws an exception like this:
java.io.IOException: Cannot run program "/opt/X.sh": java.io.IOException: error=12, Cannot allocate memory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:474)
at java.lang.Runtime.exec(Runtime.java:610)
at java.lang.Runtime.exec(Runtime.java:448)
at java.lang.Runtime.exec(Runtime.java:345)
...
Caused by: java.io.IOException: java.io.IOException: error=12, Cannot allocate memory
at java.lang.UNIXProcess.
at java.lang.ProcessImpl.start(ProcessImpl.java:81)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:467)
... 4 more
These are the status and environment for it:
Top: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 16405 root 19 0 6484m 5.1g 10m S 101 86.7 4:09.11 java Free: total used free shared buffers cached Mem: 6108084 5616532 491552 0 2244 185100 -/+ buffers/cache: 5429188 678896 Swap: 2104472 12584 2091888 |
As shown before, the program has hold about 87% memory. When the memory usage is low, there is no exception throwed. It could be why java program fails to process “Runtime.exec()”.
The Official Explains:
|
||||||||||||||||||||||
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5049299 |
Cause Detail:
This issue dues to the operating mechanism of “Runtime.exec” in Java.
In Java program, “ProcessBuilder.start” and “Runtime.exec” use fork() on *NIX system, which allocates the child process the same amount of memory as the parent process. This will double the used memory for a short time. So when the Java main process has used over 50% memory, it will absolutely never launch a child process using “Runtime.exec” successful, even the process needs almost no memory.
Solutions:
There are three workable solutions:
1. The middleware of Tanuki may solve this problem. The question is, it is complicated and also expensive.
See- http://wrapper.tanukisoftware.com/doc/english/child-exec.html
2. Separate the process using “Runtime.exec” from the main process into a new java process. So when the “Runtime.exec” is called ,it will only double the memory of the new process, using almost no memory.
which means:
a. When start/stop the main process, the “Runtime.exec” process should be started/stopped at the same time.
b. Add an independent socket in the main process to communicate with the new process. The exec command will be delivered to the new process to execute.
This will surely increase the complexity and maintenance of the system.
3. Update JDK1.6 to JDK1.7
This bug is fixed in JDK1.7 ,using new invoking mechanism of external program.
(Pipes be tested in JDK snapshot release: build 1.7.0-b147,passed with no exceptions; it also reduced the memory usage for about 20%)
This will need no modification for current source code.
Quote:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5049299
http://hi.baidu.com/lewutian/blog/item/3a60a2fa553f6115a9d31172.html
http://www.cnblogs.com/happyy/archive/2010/11/28/1890111.html
http://wrapper.tanukisoftware.com/doc/english/child-exec.html