Я получаю исключение NullPointerException в куске кода, который не может его выбросить. Я начинаю думать, что нашел ошибку в JRE. Я использую javac 1.8.0_51 в качестве компилятора, и проблема возникает как в jre 1.8.0_45, так и в последней версии 1.8.0_60.NullPointerException, в котором он не может быть выброшен
Линия, выбрасывающая исключение, находится внутри цикла, который находится внутри функции лямбда-замыкания. Мы запускаем такое замыкание в искре 1.4. Строка выполняется 1-2 миллиона раз, и я получаю ошибку не детерминистически, с тем же вводом, один раз каждые 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 никогда не нулевой, так как у вас есть «новые» несколько строк выше
- largeIndex является примитивным
- элемент никогда не является нулевым, поскольку он уже используется несколько строк выше
- 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] += ....;
Я дал взглянуть на байткод в файл класса и не нашел ничего странного. Вы правильно имеете ссылку на foo и largeIndex в стеке до iconst_1, isub и daload.
Я просто отправляю это, чтобы собрать идеи, прежде чем думать об ошибке jre. Кто-нибудь из вас испытал тот же самый класс проблем с использованием искры? или лямбда-функции в целом. Возможно ли запустить jvm с флагом отладки, чтобы помочь мне понять это странное поведение? Или я должен где-то передать вопрос кому-то?
* Я получаю исключение NullPointerException в фрагменте кода, который не может его выбросить *. ИМО линия кажется хорошим кандидатом на «NPE». Как вы заполняете 'iterable'? поскольку вы объясняете больше проблему передачи данных или целостности. –
Почему вы не думаете, что код может вызывать NPE? Тот факт, что это так, должен быть признаком, если не доказательством того, что он действительно может выбросить NPE. – skyking
Является ли * body * 'getFoo()' потенциально бросать NPE? Пожалуйста, покажи нам это. Возможно, трассировка стека опустила некоторый встроенный код или что-то в этом роде. –