I want to be able to execute the .Jar file, and if the heap space isn't set big enough, it should launch a new JVM with the same .Jar file, but set with a bigger heap space, and then close the first JVM and .Jar.
I've tried using the ProcessBuilder, but I can't get it to work.
It has to work cross platform.
-ONi
I have found the solution, and it works cross platform. To restart the JVM from code, use the following. This answer is taken from another question I found after hours of search in here. If you want, you can follow it with an System.exit(0), to terminate the JVM that started the new process, after a call to this method.
public static void startSecondJVM() throws Exception {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-Xmx1024m", "-cp",
classpath,
Main.class.getName());
Process process = processBuilder.start();
}
You can launch java with an initial heap size, and also specify a maximum heap size which will be only be used as required. I'm not sure what you're trying to do but it might emulate the behaviour you want?
java -Xms256m -Xmx1g -jar myapp.jar
In this example you start with 256M, if the app needs more memory it will take it, incrementally, up until 1G.
You might try combining these two sources.
MemoryRecoveryTest.java
Makes attempts to recover from an OutOfMemoryError
.
/*License - LGPL
<h3>Recovery from an OutOfMemory Error</h3>
<p>The JavaDocs for Error state, in the first sentence..
<blockquote>"An Error is a subclass of Throwable that indicates
serious problems that a reasonable application should
not try to catch."</blockquote>
<p>This advice has led to the fallacy that an OutOfMemoryError
should not be caught and dealt with.But this demo. shows
that it is quite easy to recover to the point of providing
the user with meaningful information, and advice on how to
proceed.
<p>I aim to make my applications 'unreasonable'.;-)
*/
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
/** A demo. showing recovery from an OutOfMemoryError.
Our options once an OOME is encountered are relatively
few, but we can still warn the end user and provide
advice on how to correct the problem.
@author Andrew Thompson */
public class MemoryRecoveryTest {
public static void main(String[] args) {
// reserve a buffer of memory
byte[] buffer = new byte[2^10];
ArrayList<Object> list = new ArrayList<Object>();
final JProgressBar memory = new JProgressBar(
0,
(int)Runtime.getRuntime().totalMemory());
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
memory.setValue(
(int)Runtime.getRuntime().freeMemory() );
}
};
Timer timer = new Timer(500, listener);
timer.start();
JDialog dialog = new JDialog();
dialog.setTitle("Available Memory");
JPanel memoryPanel = new JPanel();
memoryPanel.add(memory);
memoryPanel.setBorder(new EmptyBorder(25,25,25,25));
dialog.add( memoryPanel );
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
dialog.addWindowListener( new WindowAdapter(){
@Override
public void windowClosing(WindowEvent we) {
System.exit(0);
}
} );
// prepare a memory warning panel in advance
JPanel memoryWarning = new JPanel();
memoryWarning.add( new JLabel(
"<HTML><BODY>There is not enough memory to" +
" complete the task!<BR> Use a variant " +
" of the application that assigns more memory.") );
try {
// do our 'memory intensive' task
while(true) {
list.add( new Object() );
}
} catch(OutOfMemoryError oome) {
// provide the VM with some memory 'breathing space'
// by clearing the buffer
buffer = null;
// tell the user what went wrong, and how to fix it
JOptionPane.showMessageDialog(
dialog,
memoryWarning,
"Out of Memory!",
JOptionPane.ERROR_MESSAGE);
}
}
}
IWantToBeBig.java
Ensures a Process
is started with a memory size specified.
import java.awt.EventQueue;
import javax.swing.JOptionPane;
import java.io.File;
class IWantToBeBig {
public static void main(String[] args) throws Exception {
if (args.length==0) {
ProcessBuilder pb = new ProcessBuilder(
"java",
"-jar",
"-Xmx512m",
"big.jar",
"anArgument"
);
pb.directory(new File("."));
Process process = pb.start();
process.waitFor();
System.out.println("Exit value: " + process.exitValue());
} else {
Runnable r = new Runnable() {
public void run() {
JOptionPane.showMessageDialog(
null,
"Max Memory: " +
Runtime.getRuntime().maxMemory() +
" bytes.");
}
};
EventQueue.invokeLater(r);
}
}
}
I'd do this kind of work in an outer script file - in pseudo code:
$heap := 128
$ok := true
do {
exitCode = java -Xmx$heapM -jar myApp.jar
if (exitCode = OOME) {
heap += 128
$ok := false
}
while(!$ok)
Catch OOME and exiting with a custom code should always be possible. There's one problem with this approach - if the $heap value exceeds the maximum heap space that is possible for the target system (example: ~1.4GByte on Win32 systems) then it will not terminate.
Note: this is just an answer to the question - usually one would assign a high amount of memory and/or fight the memory leaks - but I don't know the actual requirments/restrictions