Любые ошибки или несовместимости в 64-битной JVM?

У меня есть небольшая игра, которую мы с другом пишем на Java. Это плохо закодировано, и мы работаем над его рефакторингом, но сейчас это не совсем проблема. У нас обоих есть 64-битные машины, и я предполагаю, что раньше мы использовали 32-битные JDK, но недавно у меня возникли некоторые проблемы, поэтому я удалил все JDK и установил последний 64-битный JDK, и я не уверен, когда, но мой друг тоже сейчас работает 64-битный JDK. Наша игра работала нормально на 32-битной JDK, но с 64-битной версией игра не запустится. Я пытался отладить его с помощью затмения, но это было немного больно.

Наша игра является сетевой и многопоточной, и я думаю, что у нас есть некоторые проблемы с тем, как мы синхронизировали вещи (я не до конца понимал всю идею синхронизации, когда писал ее раньше), например. мы синхронизировали наши методы run(), что не имеет никакого эффекта, но, несмотря на глупости больших частей нашего кода, этот материал все еще работает на 32-битной JVM (Windows и Linux).

Игра начинается, когда один человек ведет игру, а затем другие могут присоединиться, пока хост не решит начать игру. Затем он посылает подсказку всем игрокам, спрашивая, хотят ли они начать, и если все говорят "да", игра начинается. В 64-битной JVM происходит то, что она отправляет сообщение, но кажется, что ответ теряется или что-то в этом роде, или сервер неправильно считает, что все в порядке, потому что игра на самом деле не запускается. На самом деле, хост получает еще несколько сообщений, которые не получают другие игроки, и начинает игру немного дальше, но сервер, похоже, застрял где-то.

Есть идеи, в чем может быть проблема? Наш код на github, если кто-то хочет посмотреть. Я был бы очень рад, если бы вы это сделали, но я не ожидаю, что кто-нибудь пробежится по нашему уродливому коду. Спасибо!

Кстати, мы оба работаем на 64-битной Windows Vista и JDK 1.6 u12 и u14, но мы также работаем под Linux, хотя я еще не смог протестировать его на 64-битной Linux JVM. О, подробнее о том, почему я уверен, что это 64-битная версия JVM:

Таким образом, мы работали над этим в основном в осеннем семестре, и прекратили работать над этим некоторое время. Через 6 месяцев мы снова поднимаем его, шатаемся по нашему ужасному коду и начинаем пытаться его почистить. Тогда мы понимаем, что ни один из нас не может запустить его должным образом. Я пытаюсь найти ревизию, которая работает, но я перехожу к последней ревизии до того, как мы начали работать над ней этим летом, и она все еще не работает. Затем я даже проверил некоторые двоичные файлы (.jars), которые я скомпилировал ранее, и даже самая ранняя версия, которая у меня есть, не работает на 64-битной JVM. Затем я зарегистрировал 32-битную виртуальную машину Linux с Sun JDK1.6 JVM, и она работала нормально. Таким образом, я почти уверен, что это 64-битная проблема, так как раньше те же двоичные файлы работали отлично.

Я также заметил, что Vista по какой-то причине назначала адреса IPv6 моим сокетам при подключении к серверу на моем собственном компьютере (0:0:0:0:0:1 вместо 127.0.0.1), но я исправил все, что был специфичным для IPv4, и он все еще не работает.

На самом деле я только что создал еще одну проблему в своем репозитории github, и это совсем другой рассказ о горе, поэтому я не могу сейчас протестировать мою последнюю сборку на другом компьютере. Но последняя сборка перед рефакторингом отлично работает на 32-битной JVM с двухъядерным процессором, поэтому это не похоже на состояние гонки.

О, другое дело, точно такая же проблема работает под OpenJDK 6 64 bit под Linux. Я предполагаю, что это условие гонки, которое так или иначе выявляет 64-битная версия.

4 ответа

Решение

Мы выяснили, в чем проблема. В одной части был цикл, где поток ждал чего-то, чтобы стать готовым, над которым работал другой поток, за исключением того, что это был просто цикл (! Ready){}. Кажется, что в 64-битных потоках JVM не происходит прерывание или что-то в этом роде, потому что в 32-битной JVM этот цикл будет прерван, а затем другой поток завершит работу и установит для переменной значение true, но не в 64-битной JVM. Теперь я понимаю, что мы должны были использовать wait / notify и lock для этого, но, по крайней мере, временное использование sleep() исправило это. Не совсем гонка, скорее странная модель потоков, так что я не принимаю другие ответы, так как они не ответили на вопрос, который я задал.

Игра начинается, когда один человек ведет игру, а затем другие могут присоединиться, пока хост не решит начать игру. Затем он посылает подсказку всем игрокам, спрашивая, хотят ли они начать, и если все говорят "да", игра начинается. В 64-битной JVM происходит то, что она отправляет сообщение, но кажется, что ответ теряется или что-то в этом роде, или сервер неправильно считает, что все в порядке, потому что игра на самом деле не запускается. На самом деле, хост получает еще несколько сообщений, которые не получают другие игроки, и начинает игру немного дальше, но сервер, похоже, застрял где-то.

Это звучит так, как будто это может быть состояние гонки, то есть дефект или отсутствие синхронизации. Поскольку условия гонки зависят от времени, почти все (включая переключение JVM) может вызвать их проявление.

Я перестал бы беспокоиться о 64-битной и 32-битной системах и попытался бы диагностировать реальную проблему. Поскольку в нем задействовано несколько машин, к сожалению, это будет очень сложно (что обычно имеет место в условиях гонки).

Лучший способ сделать это, вероятно, убедиться, что все машины имеют синхронизированные часы с использованием NTP, а затем записать в журнал отправку, получение и обработку сообщений с отметками времени в миллисекундах, чтобы вы могли видеть, где сообщения теряются или не обрабатываются должным образом.

Вы работаете с процессом Java с параметром -d64? Если нет, то я почти уверен, что вы все еще используете JVM в 32-битном режиме, и ваша проблема может быть связана с окружением или ОС, а не с разрядностью.

Я не ожидал бы, что 64 против 32 вызовут какие-либо проблемы в этом случае, многопоточность, скорее всего, будет вашей причиной

Слава за использование сырых сокетов, но их очень сложно получить правильно. Подумайте об использовании библиотеки для своего сетевого стека, такой как Apache Mina, если, конечно, цель проекта - написать собственный код сокета. Обязательно прочтите краткое руководство. Это текстовый протокол, который напрямую связан с тем, что вы используете.

Примечание: синхронизация наклеивания на каждом методе и использование finalize - признаки плохих вещей / запахов кода

Другие вопросы по тегам