2015-10-02 7 views
13

スローできないコードにNullPointerExceptionが発生します。 私はJREにバグを見つけたと思っています。コンパイラとしてjavac 1.8.0_51を使用していますが、問題はjre 1.8.0_45と最新の1.8.0_60の両方で発生します。throwできない場所でNullPointerExceptionがスローされる

例外をスローする行は、ループ内にあります。これはクロージャーラムダ関数内にあります。私たちは、このような閉鎖を火花1.4で実行しています。 行は1〜200万回実行されており、同じ入力を3回または4回実行するごとに確定的なエラーは発生しません。

私はここでのコードの関連部分を貼り付けています:

 JavaRDD .... mapValues(iterable -> { 
       LocalDate[] dates = ... 
       long[] dateDifferences = ... 

       final double[] fooArray = new double[dates.length]; 
       final double[] barArray = new double[dates.length]; 
       for (Item item : iterable) { 
        final LocalDate myTime = item.getMyTime(); 
        final int largerIndex = ... 
        if (largerIndex == 0) { 
         ... 
        } else if (largerIndex >= dates.length - 1) { 
         ... 
        } else { 
         final LocalDate largerDate = dates[largerIndex]; 
         final long daysBetween = ... 
         if (daysBetween == 0) { 
          ... 
         } else { 
          double factor = ... 
          // * * * NULL POINTER IN NEXT LINE * * * // 
          fooArray[largerIndex - 1] += item.getFoo() * factor; 
          fooArray[largerIndex] += item.getFoo() * (1 - factor); 
          barArray[largerIndex - 1] += item.getBar() * factor; 
          barArray[largerIndex] += item.getBar() * (1 - factor); 
         } 
        } 
       } 
       return new NewItem(fooArray, barArray); 
      }) 
      ... 

は、私は、コードを解析し始めたとことがわかった:あなたは の上に「新しい」数行を持っているので

  • fooArrayがnullになることはありません
  • largerIndexはプリミティブです
  • アイテムは既に数行上にあるため、nullではありません
  • getfooは()なしアンボクシングのダブル
  • 要因は

プリミティブで返し、私はそれをローカルに同じ入力を実行してデバッグすることはできません。これは、スパーククラスタ上で実行されます。だから私はスローラインの前にいくつかのデバッグのprintlnを追加しました:

System.out.println("largerIndex: " + largerIndex); 
System.out.println("foo: " + Arrays.toString(foo)); 
System.out.println("foo[1]: " + foo[1]); 
System.out.println("largerIndex-1: " + (largerIndex-1)); 
System.out.println("foo[largerIndex]: " + foo[largerIndex]); 
System.out.println("foo[largerIndex - 1]: " + foo[largerIndex - 1]); 

そして、これが出力されます。

largerIndex: 2 
foo: [0.0, 0.0, 0.0, 0.0, ...] 
foo[1]: 0.0 
largerIndex-1: 1 
foo[largerIndex]: 0.0 
15/10/01 12:36:11 WARN scheduler.TaskSetManager: Lost task 0.0 in stage 7.0 (TID 17162, host13): java.lang.NullPointerException 
    at my.class.lambda$mymethod$87560622$1(MyFile.java:150) 
    at my.other.class.$$Lambda$306/764841389.call(Unknown Source) 
    at org.apache.spark.api.java.JavaPairRDD$$anonfun$toScalaFunction$1.apply(JavaPairRDD.scala:1027) 
    ... 

のでのfoo [largerIndex - 1]は現在、ヌル・ポインタを投げています。また、次はそれをスローします。注:以下の

int idx = largerIndex - 1; 
foo[idx] += ...; 

でもないが:

foo[1] += ....; 

私は、クラスファイル内のバイトコードを見てみましたし、奇妙な何も見つかりませんでした。 iconst_1、isub、およびdaloadの前に、スタック内のfooとlargerIndexへの参照が正しくあります。

jreバグを考える前にアイデアを集めるためにこれを投稿しています。 スパークを使って同じクラスの問題を経験した人はいますか?またはラムダ関数を使用します。この奇妙な動作を理解するのに役立つデバッグフラグを付けてjvmを実行することは可能ですか?または、どこかの誰かに問題を提出する必要がありますか?

+0

*それを投げることのできないコードでNullPointerExceptionが発生する*。 IMOは、「NPE」の良い候補に見える。あなたはどのように 'iterable'を設定しますか?あなたが説明していることは、より多くのデータ転送や整合性問題のようです。 –

+0

コードがNPEを投げることができると思わないのはなぜですか?それが実際にNPEを投げることができるという証拠ではないにしても、それは兆候でなければならない。 – skyking

+6

'getFoo()'の* body *は潜在的にNPEを投げますか?それを見せてください。スタックトレースでインラインコードなどが省略されている可能性があります。 –

答えて

2

それはここで説明したもの(JITの問題)と非常に同様の問題であるようにこれは私になります。それは毎回発生しないこと、それが「不可能」であることを、あなたの観察 http://kingsfleet.blogspot.com.br/2014/11/but-thats-impossible-or-finding-out.html

コードの読み込みがそこに記述されているのとまったく同じ場合に発生します。 (正しいクラス/メソッド名を指定する必要がある)のようなJIT'edされているから、あなたの方法を除外するために、コマンドラインオプションを使用し、それを見つけるために:

-XX:CompileCommand=exclude,java/lang/String.indexOf 

それとも

を使用して、それを完全にオフに切り替えることにより、
-Xint 

これはあまりにも劇的かもしれません。

+1

助けようとしたすべての人々のおかげで、残念ながら私はもはや提案された変更を行うことができません。私たちはコードで前進し、エラーは自動的に消え去った。私はおそらく問題を解決するので、この答えを受け入れる – Jack

関連する問題