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

Posted

技术标签:

【中文标题】用更大的堆空间重新启动 JVM【英文标题】:Re launch JVM with bigger heap space 【发布时间】:2011-08-29 12:26:26 【问题描述】:

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

我尝试过使用 ProcessBuilder,但我无法让它工作。

它必须跨平台工作。

-ONi

【问题讨论】:

为什么要启动一个新的 JVM 而不是简单地使用足够高的最大堆大小和 permgen 大小? 大概你只需要在内存用完后使用更大的堆大小。一旦内存不足,您将无法启动另一个进程。 我发现不同平台上不同的JVM默认分配的内存是不一样的。因此,我需要能够即时设置它。此外,我想要一个简单的体验,你只需双击 Jar,剩下的就交给它了。如果不涉及终端,则用户不能设置任何标志。 【参考方案1】:

我会在外部脚本文件中做这种工作 - 用伪代码:

$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),那么它将不会终止。

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

【讨论】:

【参考方案2】:

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

java -Xms256m -Xmx1g -jar myapp.jar

在此示例中,您从 256M 开始,如果应用需要更多内存,它将逐步占用,直到 1G。

【讨论】:

你是说-Xms=256m -Xmx=1g还是-ms=256m -mx=1g 我知道如何设置堆空间。否则我将无法自己运行代码。问题是,如何重新启动一个已经在运行的具有更多堆空间的 JVM。 我还是不明白你为什么不只是为每个进程设置最大可用堆空间,并且初始大小更小。【参考方案3】:

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

【讨论】:

【参考方案4】:

您可以尝试结合这两个来源。

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

【讨论】:

以上是关于用更大的堆空间重新启动 JVM的主要内容,如果未能解决你的问题,请参考以下文章

JVM优化

JVM 的堆大小不断增加(但 usedMemory() 不断减少)

2022-01-07:下一个排列。实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。 如果不存在下一个更大的排列,则将数字重新排列成

如何在 IIS 7.5 中配置应用程序池在停止时自动重新启动?

Leetcode练习(Python):数组类:第31题:实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 如果不存在下一个更大的排列,则将数字重新排列成最小的排列

为啥子元素不能用更大的值覆盖父元素的不透明度?