Откуда берется изменчивость в потреблении стека?

Во время выполнения тестового кода из этот вопрос и возиться со стеком потоков JVM размер, я обнаружил, что результаты не обязательно повторялись: были значения размера стека, для которых программа иногда выдавала java.lang.StackOverflowError, но иногда нет.

Мой вопрос: «Что вызывает изменение в потреблении пространства стека?»

Кроме того, можно ли поместить стек прерывания в основной поток этой программы? Будут ли результаты такими же недетерминированными для других реализаций JVM и/или операционных систем?

Тестовый код

public class PointlessRecursion {

    private static final long N = 1 << 15;

    private static long addOne(long n) {
        return (n < 2) ? n : 1 + (addOne(n - 1));
    }

    public static void main(String[] args) {
        try {
            long x = addOne(N);
            System.out.println(x);
            assert(x == N);
            System.exit(0);
        } catch (StackOverflowError e) {
            System.exit(1);
        } catch (Throwable t) {
            System.err.println(t.toString());
            System.exit(2);
        }
    }
}

Глупый сценарий bash для запуска тестовой программы несколько раз для каждого параметра размера стека

#! /bin/bash
s=2000
while [ $s -lt 4100 ] ; do
    i=0
    pass=0
    fail=0
    while [ $i -lt 10 ] ; do
        java -Xss${s}k -cp ~/bin/classes PointlessRecursion > /dev/null
        if [ $? -eq 0 ] ; then
            pass=$((pass+1))
        elif [ $? -eq 1 ] ; then
            fail=$((fail+1))
        fi
        i=$((i+1))
    done
    echo ss=$s pass=$pass fail=$fail
    s=$(($s+100))
done

Результаты

$ java -version
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)
$ ~/bin/stack-test.sh
ss=2000 pass=0 fail=10
ss=2100 pass=1 fail=9
ss=2200 pass=0 fail=10
ss=2300 pass=2 fail=8
ss=2400 pass=1 fail=9
ss=2500 pass=1 fail=9
ss=2600 pass=2 fail=8
ss=2700 pass=6 fail=4
ss=2800 pass=3 fail=7
ss=2900 pass=1 fail=9
ss=3000 pass=3 fail=7
ss=3100 pass=3 fail=7
ss=3200 pass=6 fail=4
ss=3300 pass=2 fail=8
ss=3400 pass=4 fail=6
ss=3500 pass=10 fail=0
ss=3600 pass=9 fail=1
ss=3700 pass=10 fail=0
ss=3800 pass=10 fail=0
ss=3900 pass=10 fail=0
ss=4000 pass=10 fail=0

person David J. Liszewski    schedule 13.09.2010    source источник
comment
Кстати, 100% отказ для размеров стека ‹= 1500K и 100% успех для размеров стека ›= 3700K.   -  person David J. Liszewski    schedule 13.09.2010


Ответы (2)


Я не удивлюсь, если это как-то связано со временем запуска компилятора HotSpot, особенно если вы работаете в многоядерной системе.

EDIT: Чтобы проверить это, вы можете запустить свой тест с помощью -Xint. ЕСЛИ вы начинаете получать воспроизводимые результаты, то недетерминированное поведение, вероятно, вызвано компилятором HotSpot.

person gpeche    schedule 13.09.2010
comment
БИНГО! У меня был момент, чтобы повторно запустить тесты с -Xint, и вариативность исчезла. Спасибо! - person David J. Liszewski; 17.09.2010

Я не наблюдаю такого поведения. В моей среде (Windows 7 x64, 1.6.0_19 x86 JDK) они постоянно терпят неудачу до определенного момента, а затем начинают проходить при ss=1400 (я уменьшил его, поскольку все они проходили с вашими параметрами).

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

Вы уверены, что на самом деле вы ловите StackOverflowError? Я бы поймал эту ошибку исключительно вместо общего Throwable, чтобы убедиться, что это не что-то еще, например OutOfMemoryError.

//...
} catch (StackOverflowError e) {
    System.exit(1);
}

Таким образом, он напечатает трассировку стека, если на самом деле это не StackOverflowError, который вы получаете.

person Mark Peters    schedule 13.09.2010
comment
Это определенно (очень длинная) трассировка SOE, например: ... Попробую и на другой ОС. Спасибо за точку данных. - person David J. Liszewski; 13.09.2010
comment
В Windows я получаю меньше вариативности, но она все же есть. Для меня результаты не были детерминированными между 1320k и 1370k. - person David J. Liszewski; 14.09.2010