Java 使用更大的堆空间重新启动JVM

Java 使用更大的堆空间重新启动JVM,java,jvm,heap,reboot,relaunch,Java,Jvm,Heap,Reboot,Relaunch,我希望能够执行.Jar文件,如果堆空间设置得不够大,它应该使用相同的.Jar文件启动一个新的JVM,但是使用更大的堆空间进行设置,然后关闭第一个JVM和.Jar 我尝试过使用ProcessBuilder,但无法使其工作 它必须跨平台工作 -ONi我会在外部脚本文件中执行此类工作-使用伪代码: $heap := 128 $ok := true do { exitCode = java -Xmx$heapM -jar myApp.jar if (exitCode = OOME) {

我希望能够执行.Jar文件,如果堆空间设置得不够大,它应该使用相同的.Jar文件启动一个新的JVM,但是使用更大的堆空间进行设置,然后关闭第一个JVM和.Jar

我尝试过使用ProcessBuilder,但无法使其工作

它必须跨平台工作


-ONi

我会在外部脚本文件中执行此类工作-使用伪代码:

$heap := 128
$ok := true
do {
  exitCode = java -Xmx$heapM -jar myApp.jar
  if (exitCode = OOME) {
    heap += 128
    $ok := false
  }
while(!$ok)
捕获OOME并使用自定义代码退出应该始终是可能的。这种方法有一个问题-如果$heap值超过目标系统可能的最大堆空间(例如:Win32系统上为~1.4GByte),那么它将不会终止


注意:这只是对这个问题的回答-通常会分配大量内存和/或防止内存泄漏-但我不知道实际的要求/限制

您可以使用初始堆大小启动java,还可以指定仅在需要时使用的最大堆大小。我不知道你想做什么,但它可能会模仿你想要的行为

java -Xms256m -Xmx1g -jar myapp.jar

在本例中,您从256M开始,如果应用程序需要更多内存,它将以增量方式占用它,直到1G。

我找到了解决方案,它可以跨平台工作。要从代码中重新启动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();
}

你可以尝试结合这两个来源

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);
        }
    }
}

为什么要启动一个新的JVM,而不是简单地使用足够高的最大堆大小和永久大小?可以推测,一旦内存耗尽,您只需要使用更大的堆大小。一旦内存耗尽,就无法启动另一个进程。我发现,在不同平台上为不同JVM分配的默认内存是不同的。因此,我需要能够设置它的飞行。此外,我想要一个简单的体验,您只需双击Jar,它就可以处理其余的事情。如果没有涉及终端,用户就不能设置任何标志。你是说,
-Xms=256m-Xmx=1g
还是
-ms=256m-mx=1g
我知道如何设置堆空间。否则我就不能自己运行代码了。问题是,如何用更多的堆空间重新启动已经运行的JVM。我仍然不明白为什么不为每个进程设置最大可用堆空间,并使用较小的初始大小。
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);
        }
    }
}