java - Relanzar JVM con mayor espacio de almacenamiento
heap reboot (4)
Quiero poder ejecutar el archivo .Jar, y si el espacio del montón no está configurado lo suficientemente grande, debería iniciar una nueva JVM con el mismo archivo .Jar, pero establecer con un espacio de montón más grande, y luego cerrar el primero JVM y .Jar.
Intenté usar ProcessBuilder, pero no puedo hacer que funcione.
Tiene que funcionar multiplataforma.
-ONI
Encontré la solución y funciona en varias plataformas. Para reiniciar la JVM desde el código, use lo siguiente. Esta respuesta proviene de otra pregunta que encontré después de horas de búsqueda aquí. Si lo desea, puede seguirlo con un System.exit (0) para finalizar la JVM que inició el nuevo proceso, después de una llamada a este método.
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();
}
Haría este tipo de trabajo en un archivo de script externo, en pseudo código:
$heap := 128
$ok := true
do {
exitCode = java -Xmx$heapM -jar myApp.jar
if (exitCode = OOME) {
heap += 128
$ok := false
}
while(!$ok)
Capturar OOME y salir con un código personalizado siempre debería ser posible. Hay un problema con este enfoque: si el valor de $ heap excede el espacio de almacenamiento dinámico máximo que es posible para el sistema de destino (ejemplo: ~ 1.4 GB en sistemas Win32), no finalizará.
Nota: esta es solo una respuesta a la pregunta: por lo general, uno asignaría una gran cantidad de memoria y / o lucharía contra las fugas de memoria, pero no conozco los requisitos / restricciones reales.
Puede iniciar Java con un tamaño de almacenamiento dinámico inicial y también especificar un tamaño de almacenamiento dinámico máximo que solo se usará según sea necesario. No estoy seguro de lo que estás tratando de hacer, pero podría emular el comportamiento que deseas?
java -Xms256m -Xmx1g -jar myapp.jar
En este ejemplo, comienza con 256M, si la aplicación necesita más memoria, la llevará, de forma incremental, hasta 1G.
Puede intentar combinar estas dos fuentes.
MemoryRecoveryTest.java
Intenta recuperarse de un 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
Asegura que un Process
se inicie con un tamaño de memoria especificado.
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);
}
}
}