Что делать, если новое не удается? - PullRequest
12 голосов
/ 24 января 2011

В C ++ и C #, когда new не может выделить достаточную память, он генерирует исключение.

Я не смог найти никакой информации о поведении new в Java. Так что же произойдет, если новый сбой в Java (не хватает памяти)?

Ответы [ 5 ]

25 голосов
/ 24 января 2011

Если вы конкретно имеете в виду сбой выделения памяти, тогда он должен выбросить OutOfMemoryError

Брошенный, когда виртуальная машина Java не может выделить объект, потому что ему не хватает памяти, и сборщик мусора больше не может сделать доступной память.

Как и все подклассы Error, это обычно невосстановимое состояние, даже если технически вы можете его поймать:

Ошибка - это подкласс Throwable, который указывает на серьезные проблемы, которые разумное приложение не должно пытаться устранить. Большинство таких ошибок являются ненормальными условиями. Ошибка ThreadDeath, хотя и является «нормальным» условием, также является подклассом Error, поскольку большинству приложений не следует пытаться ее перехватить.

Метод не обязан объявлять в своем предложении throws любые подклассы Error, которые могут быть выброшены во время выполнения метода, но не обнаружены, поскольку эти ошибки являются ненормальными условиями, которые никогда не должны возникать.

4 голосов
/ 24 января 2011

Когда Java не может получить достаточно памяти для выделения объекта, вы получите OutOfMemoryError .

На практике исключение может занять довольно много времени, чтобы его фактически выдало JVM.Когда возникает проблема с памятью, JVM сначала пытается собрать как можно больше памяти.В зависимости от конфигурации JVM (параметры GC и максимальная память кучи) цикл GC может занять от нескольких секунд до нескольких минут, если для Xmx установлено несколько гигабайт.Еще хуже, в зависимости от необходимой памяти, JVM может выполнить несколько циклов GC, прежде чем выдать исключение.

Когда исключение является throw, оно обрабатывается как любое необработанное исключение.Как таковой он будет распространяться на вершину стека вызовов потока, где возникло исключение.Поскольку исключение не обработано, поток покажет трассировку стека на System.err перед смертью.Это все.В однопоточной программе это приведет к ее завершению.В многопоточной программе эта смерть потока может освободить достаточно памяти для продолжения работы программы в нестабильной конфигурации.

Моя рекомендация, если вас беспокоит проблема с памятью, - это зарегистрироваться и UncaughtExceptionHandler для уничтожения вашей программы при возникновении проблемы с памятью, поскольку, безусловно, лучше остановить вашу программу, чем позволить ей работать в неопределенном состоянии, когда никто не знает.

Вы можете прочитать следующие статьи из Heinz Kabutzпо теме:

2 голосов
/ 24 января 2011

Немного больше о OOME .

/*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);
        }
    }
}
2 голосов
/ 24 января 2011

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

1 голос
/ 24 января 2011

Вы можете перехватить исключения OutOfMemoryException, но это не рекомендуется.Однако, если это не проблема кодирования / проектирования - сборщик мусора должен позаботиться об управлении кучей.

Если вы думаете, что будете выполнять большой объем обработки данных и можете запустить память, тогда вы всегда можете проверитьсвободное место, доступное до начала выполнения (скопировал фрагмент кода из этой ссылки ).

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...