Почему ошибка переполнения стека возникает именно после 518669? - PullRequest
2 голосов
/ 09 марта 2010

Я создал Java-программу для подсчета до бесконечности:

class up {

    public static void up (int n) {
        System.out.println (n) ;    
        up (n+1) ;
}

    public static void main (String[] arg) {
        up (1) ;

}
}

На самом деле я не ожидал, что она туда попадет, но то, что я заметил, было немного любопытно, что она остановилась накаждый раз одно и то же число: 518669

Какое значение имеет это число?(или этого числа +1, я полагаю).

Ответы [ 5 ]

8 голосов
/ 09 марта 2010

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

5 голосов
/ 09 марта 2010

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

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

Вы можете изменить и то, и другое, и изменить результат.

Вы можете изменить максимальный размер стека, доступный вашей JVM, передав флаг -Xss, например:

java -Xss4096k MyClass

На моем компьютере с параметрами запуска по умолчанию у меня не хватает стека после 10 518 рекурсивных вызовов. Я думаю, что по умолчанию 1024k для моей установки.

Если я установлю максимальный размер стека равным 4096 КБ, как указано выше, я могу получить 50 777 рекурсивных вызовов до переполнения стека.

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

Если я добавлю оператор MyClass myClass = new MyClass(); в код (локальный экземпляр MyClass для вызова) после вашего оператора println, число вызовов, которые я могу сделать до переполнения, уменьшится с 10 518 до 9 709, как для каждого вызова, ссылки к экземпляру MyClass был сохранен.

2 голосов
/ 09 марта 2010

У вас есть конечный объем памяти, выделенный для стека вызовов. Это один и тот же объем памяти при каждом запуске приложения. Так что он перестает считать в одном и том же месте каждый раз, потому что у вас недостаточно памяти стека.

Что касается вас, я бы отформатировал в этом манноре

class up 
{
    public static void up(int n) 
    {
        System.out.println(n);    
        up(n + 1);
    }

    public static void main(String[] arg) 
    {
        up(1);

    }
}

Таким образом, намного легче понять, когда ваши блоки начинаются и заканчиваются.

0 голосов
/ 09 марта 2010

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

Нет никакой причины использовать рекурсию здесь - вы должны просто использовать цикл while.

0 голосов
/ 09 марта 2010

Чтобы ответить на ваш вопрос, закрывающая скобка метода обычно выровнена с началом метода. Так что в ваших случаях здесь, в том же столбце, что и «р» public.

...