Замедление производительности некоторого вида в возврате или параметре (Java) - PullRequest
0 голосов
/ 08 марта 2012

Я запускаю сложную многопоточную Java-игру, которая отлично работает, за исключением этой функции. При вызове этой функции приблизительно в 0,01% времени она будет вызывать заминку потока в четверть секунды. Благодаря серии отладочных линий и измерениям времени, эта функция полностью зависит от этой функции (и от трех других она точно такая же).

Использование этой функции - обеспечить уровень освещенности соседнего блока в игре с движком вокселей. Он запускается только при обновлении раздела мира, что может происходить одновременно с рендерингом.

Обратите внимание:

  • Эта функция работает точно 100% времени для ее предполагаемой функции.
  • Эта функция вызывает прерывание потока примерно в четверть секунды в 0,01% времени.
  • Переменные не синхронизированы.
  • Функция никогда не вызывается более одного раза за раз в программе.
  • Все переменные являются допустимыми полями большего несинхронизированного класса.
  • Все переменные являются целыми числами.
  • Массив light[][][] представляет собой byte[][][].
  • Этот метод никогда не вызывается более одного раза за раз, поскольку он синхронизируется более крупным методом с широким интервалом.

Я почти уверен, что внешняя синхронизация не является проблемой.

Какая часть (и) этой функции может вызывать проблемы с синхронизацией потоков, чрезмерным использованием ЦП или заполнением стека, и как я могу улучшить производительность, чтобы избавиться от этих проблем рендеринга?

public byte nsleftlighting(int[] coords){
    if(coords[0]<0)return 16;
    difx=chunkedx-chunks[coords[0]].X;
    difz=chunkedz-chunks[coords[0]].Z;
    if(coords[1]==0){ 
        if(-difx<=-(chunklimit)){return 16;}

        else if (-difx==0) {
            if(-difz>=0){
                proz=0;
                specialz=-difz;
            }else{
                specialz=difz-1;
                proz=1;
            }
            if(chunks[chunkxyid[1][proz][0][specialz]].loaded){
                return chunks[chunkxyid[1][proz][0][specialz]].light[15][coords[2]][coords[3]];
            }
            else{return 16;}
        } else {
            if(-difz>=0){
                proz=0;
                specialz=-difz;
            }else{
                specialz=difz-1;
                proz=1;
            }
            if(-difx>0){
                prox=0;
                specialx=-difx-1;
            }else{
                specialx=difx;
                prox=1;
            }
            if(chunks[chunkxyid[prox][proz][specialx][specialz]].loaded){
                return chunks[chunkxyid[prox][proz][specialx][specialz]].light[15][coords[2]][coords[3]];
            } else {return 16;}
        }
    }
    if(coords[1]>0){
        return chunks[coords[0]].light[coords[1]-1][coords[2]][coords[3]];
    }
    return 16;
}

Ответы [ 2 ]

2 голосов
/ 08 марта 2012

Многомерные массивы в Java не гарантированно размещаются в памяти непрерывно (я не уверен, что одномерные массивы конкретно гарантированно также являются смежными, но на практике это так). Следовательно, в зависимости от того, как вы обращаетесь к элементам, кэш ЦП может обновляться довольно часто (в отличие от доступа к последовательным или близким элементам в одномерном массиве, что довольно быстро, как для всего массива, или, по крайней мере, его непрерывный блок может быть сразу загружен в кэш, кроме того, более новые реализации JVM могут оптимизировать проверки привязки к индексу в некоторых простых - но не сложных - случаях (циклах), что делает доступ к массиву почти таким же быстрым, как и на любом языке (С)). Что именно происходит, зависит от реализации JVM и менеджера памяти. См. this для справки.

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

1 голос
/ 08 марта 2012

Я не вижу здесь ничего, что могло бы вызвать проблемы с производительностью - по крайней мере, с таким большим отклонением. Доступ к массиву должен быть чрезвычайно быстрым - даже если это 4-мерные массивы. [[Хорошие усилия на этом.]]

Четверть секунды - это не огромное количество времени, которое заставляет меня задуматься, лжет ли вам профилировщик об источнике проблемы. Возможно, он плохо реагирует на многомерные массивы или какой-то другой атрибут этого метода, который не сразу очевиден - по крайней мере для меня.

Одна возможность, пусть и удаленная, заключается в том, что ваша программа поменялась местами, и эти массивы довольно большие. Если к ним не обращаются очень часто, есть ли вероятность того, что вы увидите какой-нибудь ввод-вывод, когда некоторые страницы памяти поменялись местами?

Вы прокомментировали, что используете настенные таймеры, чтобы определить, что процедура занимает 250 мс. Вы уверены, что процессор фактически выполнял этот метод в течение этого периода времени? Может ли это быть причиной конфликта потоков, который занимает центральный процессор в какой-то другой части программы? Можете ли вы увидеть, как часто вы видите пики процессора, когда этот метод занимает много времени?

Есть ли шанс, что вы видите блокировку кучи GC, и это влияет на доступ к массиву больше, чем другие процедуры? Можете ли вы посмотреть графики памяти, чтобы увидеть, видите ли вы корреляцию? Влияет ли увеличение программы на время или частоту возникновения проблемы? Это будет более серьезной проблемой, если вы используете Java <= 1.5. </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...