Я столкнулся с довольно странной проблемой, которую я могу создать при запуске 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