В чём разница между StackOverFlowError и OutOfMemoryError?

Рейтинг: 7Ответов: 1Опубликовано: 02.03.2023

StackOverFlowError и OutOfMemoryError выбрасываются при недостатке памяти у jvm, но в чём их разница?

Ответы

▲ 10Принят

StackOverFlowError

Эта ошибка происходит, когда переполнен стек (по-английски - stack). Если кратко, то в стеке хранятся только ссылки на объекты, которые находятся в куче. Ещё в стеке хранятся примитивы и список методов, "кто кого вызвал". Вообщем StackOverFlowError происходит при зацикливании вызова методов. Например:

public static void doSomething(){
    doSomething();
}

При вызове метода doSomething() произойдёт StackOverFlowError, так как стек будет переполнен.

Чтобы исправить StackOverFlowError нужно найти такое зацикливание и убрать его. На самом деле, вызов метода из самого себя использовать можно, но делать это стоит осторожно. Это будет называться рекурсия. Вот пример использования рекурсии для вычисления факториала:

public static int factorial(int number){
    if(number < 0){
       throw new IllegalArgumentException("Число меньше 0");
    }  
    if(number == 0 || number == 1){
       return 1;
    }
    return factorial(number - 1) * number;
}

В таком случае StackOverFlowError не произойдёт, так как из метода в конце-концов будет выполнен выход.

В рекурсивных методах следует также проверять, что число, пришедшее в параметрах, не слишком большое. В противном случае может оказаться, что метод будет вызывать сам себя хоть и не бесконечное, но всё же достаточное количество раз, чтобы произошла ошибка StackOverFlowError.

OutOfMemoryError

Это ошибка происходит, когда переполнена куча (по-английски - heap). Если кратко, то в куче хранятся объекты. Именно объекты, а не ссылки на них. То есть OutOfMemoryError произойдёт тогда, когда в куче кончится место создавать объекты. Вот пример:


public class Test{

  public static void main(String [] args){ 
      Object[][] toManyObjects = new Object[1000000][1000000];
  }

}

Этот код бует скомпилирован, но при запуске произойдёт OutOfMemoryError:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at Test.main(Test.java:5)

Ведь в массиве гигантское количество объектов, и в куче нет столько места.

Конечно, никто не будет делать такие глупые ошибки. Обычно OutOfMemoryError происходит тоже при зацикливании, но не при бесконечном вызове метода, а в обычных циклах (for, while, do-while), если из таких циклов нет выхода, а в теле цикла создаются какие-либо объекты.

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

Подведу итоги

  • OutOfMemoryError происходит при переполнении кучи, а StackOverFlowError - при переполнении стека;
  • StackOverFlowError происходит при бесконечном вызове метода, а OutOfMemoryError - при зацикливании создания объектов;
  • И того, и другое нужно исправить: найти зацикливание и устранить его.

Ссылки

Статья на хабре про память в java

Ещё одна статья на хабре про память в java

Пост на английском StackOverFlow