1

この質問からテスト コードを実行し、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
4

2 に答える 2

3

特にマルチコア システムで実行している場合は、HotSpot コンパイラが起動するタイミングと関係があるとしても驚かないでしょう。

編集:これを確認するには、でテストを起動できます-Xint。再現可能な結果が得られるようになった場合、非決定的な動作はおそらく HotSpot コンパイラが原因です。

于 2010-09-13T22:32:24.897 に答える
1

私はこの行動を観察しません。私の環境(Windows 7 x64、1.6.0_19 x86 JDK)では、特定の時点まで一貫して失敗し、ss = 1400で通過し始めます(すべてパラメーターで通過していたので、それを下げました)。

私が唯一変更したのは、クラスパスを指定しないことでした (クラス ファイルと同じディレクトリからスクリプトを実行しました)。しかし、クラスパスを指定しても同じ結果が得られました。

あなたがキャッチしているのは実際に StackOverflowError であると確信していますか? 一般的な Throwable の代わりにそのエラーのみをキャッチして、OutOfMemoryError のような別のものではないことを確認します。

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

そうすれば、実際に取得している StackOverflowError ではない場合、スタックトレースが出力されます。

于 2010-09-13T19:41:21.603 に答える