Перезапустите JVM с большим пространством кучи - PullRequest
4 голосов
/ 20 мая 2011

Я хочу иметь возможность выполнять файл .Jar, и если пространство кучи не установлено достаточно большим, он должен запустить новую JVM с тем же файлом .Jar, но с большим пространством кучи, а затемзакройте первую JVM и .Jar.

Я пытался использовать ProcessBuilder, но не могу заставить его работать.

Он должен работать кроссплатформенно.

-ONi

Ответы [ 4 ]

6 голосов
/ 21 мая 2011

Я нашел решение, и оно работает кроссплатформенно.Чтобы перезапустить JVM из кода, используйте следующее.Этот ответ взят из другого вопроса, который я нашел после нескольких часов поиска здесь.Если вы хотите, вы можете использовать System.exit (0) для завершения JVM, запустившего новый процесс, после вызова этого метода.

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();
}
1 голос
/ 21 мая 2011

Вы можете попробовать объединить эти два источника.

MemoryRecoveryTest.java

Делает попытки оправиться от 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

Гарантирует, что Process запущен с указанным объемом памяти.

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);
        }
    }
}
1 голос
/ 20 мая 2011

Вы можете запустить Java с начальным размером кучи, а также указать максимальный размер кучи, который будет использоваться только по мере необходимости. Я не уверен, что вы пытаетесь сделать, но это может подражать поведению, которое вы хотите?

java -Xms256m -Xmx1g -jar myapp.jar

В этом примере вы начинаете с 256M, если приложению требуется больше памяти, оно будет постепенно увеличивать его до 1G.

0 голосов
/ 20 мая 2011

Я бы сделал такую ​​работу во внешнем файле сценария - в псевдокоде:

$heap := 128
$ok := true
do {
  exitCode = java -Xmx$heapM -jar myApp.jar
  if (exitCode = OOME) {
    heap += 128
    $ok := false
  }
while(!$ok)

Поймать OOME и выйти с пользовательским кодом всегда должно быть возможно. В этом подходе есть одна проблема - если значение $ heap превышает максимальное пространство кучи, которое возможно для целевой системы (например: ~ 1,4 ГБ в системах Win32), оно не прекратит работу.

Примечание: это всего лишь ответ на вопрос - обычно можно выделить большой объем памяти и / или бороться с утечками памяти - но я не знаю фактических требований / ограничений

...