3

マシンをビジー状態に保つためにダミーとして使用した非常に単純なforループは、JVMのすべてのプロセスをブロックしました。ストールは、最も単純なコンステレーションでも持続しました。

2つのforループ(最初のブロッキング、2番目のブロッキングではない)の例を次に示します。唯一の違いは、イテレータ「i」のタイプ、つまりintとlongです。

public class Main {
public static void main(String[] args) {

    Timer timer = new Timer();
    timer.schedule(new MyTimerHandler(), new Date(), 1000);
    float b = 1;

    // after a few seconds this loop uses 200% CPU and blocks the timer 
    for (int i=0; i<2000000000; i++) {
        b += i/3.141592;
    }
    System.out.println("Result: " + b);
    b = 1;

    // this version uses 100% CPU throughout the entire loop and doesn't block the timer
    for (long i=0; i<2000000000L; i++) {
        b += i/3.141592;
    }
    System.out.println("Result: " + b);
    timer.cancel();
 }
}
// helps to show whether the JVM is stalled or not
class MyTimerHandler extends TimerTask {
    @Override
    public void run() {
        System.out.println("timestamp=" + new Date().toString());
    }
}

2つの異なるマシン/jvmで問題を再現しました。

  • Arch Linux 3.7.7-1-ARCH ... x86_64 GNU / Linuxjavaバージョン"1.7.0_09"、Java(TM)SEランタイム環境(ビルド1.7.0_09-b05)
  • OSX 10.8.2 ... x86_64javaバージョン"1.7.0_07"、Java(TM)SEランタイム環境(ビルド1.7.0_07-b10)

更新と明確化:

  • 問題は、与えられた例を「解決」するのではなく、なぜ、何が正確に起こっているのかということです。つまり、最初のforループが2倍以上のCPUを使用し、JVMのすべてのスレッドをブロックするという奇妙な動作をするのはなぜですか。
  • サンプルコードは終了し、正しい結果が得られます。
  • タイマーはデモンストレーション用であり、問​​題はタイマーの有無にかかわらず発生します。
  • intの制限は2,000,000,000をはるかに超えています。
  • この問題は、これまでにテストされたすべてのJVMに影響します。
  • JProfilerおよびその他のデバッグツールは、最初のforループでも中断/停止します。
4

2 に答える 2

1

これは、最適化コンパイラが原因です(おそらくループを展開しようとしています)。別のスレッドで実行されるため、CPU使用率は200%になります。最初のループからメソッドを作成し、2回目に2回実行すると、期待どおりに機能します。

次のようにJVMを実行してみてください。

java -Xint Main

このオプションは、HotSpotコンパイラを無効にします。私の場合、タイマースレッドは一時停止なしで毎秒印刷されます。


で実行するとjava -XX:+PrintCompilation Main、コンパイラが最初のループの途中で「参加しなかった」と出力することがわかります。

    79    6             java.lang.String::lastIndexOf (52 bytes)
    90    1 %           test.Main::main @ 33 (141 bytes)
    timestamp=Thu Feb 14 12:10:40 PST 2013
    timestamp=Thu Feb 14 12:10:41 PST 2013
    timestamp=Thu Feb 14 12:10:42 PST 2013
    timestamp=Thu Feb 14 12:10:43 PST 2013
    timestamp=Thu Feb 14 12:10:44 PST 2013
    13202    1 %           test.Main::main @ -2 (141 bytes)   made not entrant
    timestamp=Thu Feb 14 12:10:53 PST 2013
    Result: 1.80143985E16
    13202    2 %           test.Main::main @ 85 (141 bytes)
    timestamp=Thu Feb 14 12:10:54 PST 2013
    timestamp=Thu Feb 14 12:10:55 PST 2013

ループを交換すると、2つのループの間に「参加していない」と印刷されます。

    72    6             java.lang.String::lastIndexOf (52 bytes)
    85    1 %           test.Main::main @ 33 (141 bytes)
    timestamp=Thu Feb 14 12:12:38 PST 2013
    timestamp=Thu Feb 14 12:12:39 PST 2013
    timestamp=Thu Feb 14 12:12:40 PST 2013
    timestamp=Thu Feb 14 12:12:41 PST 2013
    15415    1 %           test.Main::main @ -2 (141 bytes)   made not entrant
    Result: 1.80143985E16
    15415    2 %           test.Main::main @ 88 (141 bytes)
    timestamp=Thu Feb 14 12:12:42 PST 2013
    timestamp=Thu Feb 14 12:12:43 PST 2013
于 2013-02-14T18:32:38.370 に答える
0

Using AProVE (http://aprove.informatik.rwth-aachen.de) I proved that the first loop indeed is terminating. Please have a closer look at the other possibly non-terminating code, most likely the timer (as indicated in the comments).

于 2013-02-14T19:05:35.620 に答える