Сблъсках се с доста странен проблем, който мога да създам, когато изпълнявам Java 8. Проблемът се представя така, сякаш се случва някаква грешка във времето в самата JVM. Той е периодичен по природа, но лесно се възпроизвежда (поне в моите тестови среди). Проблемът е, че стойността на масива, която е изрично зададена, се унищожава и заменя с 0.0 при определени обстоятелства. По-конкретно, в кода по-долу array[0]
се оценява на 0.0 след ред new Double(r.nextDouble());
. След това, ако веднага погледнете съдържанието на array[0]
отново, то сега показва, че стойността е правилната стойност от 1,0. Примерен резултат от изпълнението на този тестов случай е:
claims array[0] != 1.0....array[0] = 1.0
claims array[0] now == 1.0...array[0] = 1.0`
Работя с 64-битов Windows 7 и мога да възпроизведа този проблем както от Eclipse, така и при компилиране от командния ред с JDK 1.8_45, 1.8_51 и 1.8_60. Не мога да произведа проблема при стартиране на 1.7_51. Същите резултати са демонстрирани на друга 64-битова кутия с Windows 7.
Този проблем се появи в голям, нетривиален софтуер, но успях да го съкратя до няколко реда код. По-долу е даден малък тестов случай, който демонстрира проблема. Това е доста странно изглеждащ тестов случай, но изглежда, че всички са необходими, за да причинят грешката. Използването на Random
не е задължително - мога да заменя всички r.nextDouble()
с произволна двойна стойност и да демонстрирам проблема. Интересното е, че ако someArray[0] = .45;
се замени с someArray[0] = r.nextDouble();
, не мога да репликирам проблема (въпреки че няма нищо специално за .45
). Отстраняването на грешки в Eclipse също не помага - то променя времето достатъчно, така че да не се случва повече. Дори добре поставен израз System.err.println()
ще накара проблема да не се появява повече.
Отново, проблемът е периодичен, така че за да възпроизведете проблема, може да се наложи да изпълните този тестов случай няколко пъти. Мисля, че най-много трябва да го стартирам около 10 пъти, преди да получа резултата, показан по-горе. В Eclipse му давам секунда или две след стартиране и след това го убивам, ако не се е случило. От командния ред същото - стартирайте го, ако не стане CTRL+C
да излезете и да опитате пак. Изглежда, че ако ще се случи, то става доста бързо.
Срещал съм проблеми като този в миналото, но всички те бяха проблеми с нишки. Не мога да разбера какво става тук - дори погледнах байт кода (който между другото беше идентичен между 1.7_51 и 1.8_45).
Някакви идеи какво се случва тук?
import java.util.Random;
public class Test {
Test(){
double array[] = new double[1];
Random r = new Random();
while(true){
double someArray[] = new double[1];
double someArray2 [] = new double [2];
for(int i = 0; i < someArray2.length; i++) {
someArray2[i] = r.nextDouble();
}
// for whatever reason, using r.nextDouble() here doesn't seem
// to show the problem, but the # you use doesn't seem to matter either...
someArray[0] = .45;
array[0] = 1.0;
// commented out lines also demonstrate problem
new Double(r.nextDouble());
// new Float(r.nextDouble();
// double d = new Double(.1) * new Double(.3);
// double d = new Double(.1) / new Double(.3);
// double d = new Double(.1) + new Double(.3);
// double d = new Double(.1) - new Double(.3);
if(array[0] != 1.0){
System.err.println("claims array[0] != 1.0....array[0] = " + array[0]);
if(array[0] != 1.0){
System.err.println("claims array[0] still != 1.0...array[0] = " + array[0]);
}else {
System.err.println("claims array[0] now == 1.0...array[0] = " + array[0]);
}
System.exit(0);
}else if(r.nextBoolean()){
array = new double[1];
}
}
}
public static void main(String[] args) {
new Test();
}
}
double
по своята същност не е прецизен. Сигурни ли сте, че това не е вашият проблем? - person PM 77-1   schedule 07.10.2015if
. - person bcothren   schedule 07.10.2015new Double(...)
? Това е нещо, което не бих очаквал да намеря в реалния код. @PM77-1: Съхраняването на интегралната стойност на1.0
вdouble
никога не трябва да води до такива проблеми, тъй като може да бъде представено без загуба на точност. Ако==
дава грешни резултати, бих предпочел да очаквам, че по някаква причина се използва стойност в кутия (поради грешка в JVM). - person Axel   schedule 07.10.2015Double
в опит да изляза с най-простия тестов случай. Можете ли да възпроизведете проблема? Може ли да е преждевременно да подадете сигнал за грешка? - person bcothren   schedule 07.10.20151.0d == 1.0d
пак трябва да е вярно. Винаги. - person assylias   schedule 07.10.2015-Xint
) наистина премахва проблема. Това не ми харесва като решение, но поне е причина за проблема. - person bcothren   schedule 07.10.2015-XX:-TieredCompilation
или-XX:-EliminateAllocations
е вероятно да бъде приемливо решение, което не влошава значително производителността. - person apangin   schedule 07.10.2015