Как я могу избежать задержек сборки "мусора" Java игр? (Лучшие практики) [закрываются]

63
задан Gabe 20 March 2010 в 18:08
поделиться

3 ответа

Я работал над мобильными играми Java ... Лучший способ избежать GC'ing-объектов (которые, в свою очередь, должен запускать сборщик мусора в тот или иной момент, а должен убивать производительность вашей игры) просто для того, чтобы вообще не создавать их в вашем основном игровом цикле.

Не существует "чистого" способа справиться с этим, и сначала я приведу пример ...

Обычно у вас, скажем, 4 шара на экране в точках (50,25), (70,32), (16,18), (98,73). Итак, вот ваша абстракция (упрощенная для этого примера):

n = 4;
int[] { 50, 25, 70, 32, 16, 18, 98, 73 }

Вы "выталкиваете" второй шар, который исчезает, ваш int [] становится:

n = 3
int[] { 50, 25, 98, 73, 16, 18, 98, 73 }

(обратите внимание, что мы даже не заботимся об "очистке" 4-й шар (98,73), мы просто отслеживаем количество оставшихся шаров).

К сожалению, ручное отслеживание объектов. Именно так это делается в большинстве современных хорошо работающих Java-игр, выпущенных на мобильных устройствах.

Что касается строк, вот что я бы сделал:

  • при инициализации игры, предварительная отрисовка с использованием drawText (...) только один раз чисел от 0 до 9, которые вы сохраняете в Массив BufferedImage [10] .
  • при инициализации игры выполните предварительную отрисовку один раз «Ваш счет:»
  • если «Ваш счет:» действительно нужно перерисовать (потому что, скажем, он прозрачный), тогда перерисуйте его из предварительно сохраненного цикла BufferedImage
  • , чтобы вычислить цифры оценки, и добавьте после «Ваша оценка:» каждую цифру вручную одну за другой (копируя каждую время соответствующей цифры (от 0 до 9) из вашего BufferedImage [10] , где вы их предварительно сохранили.

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

Еще одно «преимущество» этой «нулевой оценки создания объекта» заключается в том, что тщательное кэширование изображений и повторное использование шрифтов на самом деле не «ручное выделение / освобождение объекта» , это действительно просто аккуратное кеширование.

Это не «чисто», это не «хорошая практика», но именно так это делается в первоклассных мобильных играх (например, Uniwar).

И это быстро. Чертовски быстро. Быстрее, чем что-либо , связанное с созданием объекта.

PS: На самом деле, если вы внимательно посмотрите на несколько мобильных игр, вы заметите, что часто шрифты на самом деле являются не системными / Java-шрифтами, а шрифтами, идеально подходящими для каждой игры (здесь я просто привел пример того, как для кэширования системного / Java-шрифта, но, очевидно, вы также можете кэшировать / повторно использовать пиксельный / растровый шрифт).

56
ответ дан 24 November 2019 в 16:26
поделиться

Если вы не хотите предварительно отрисовывать текст, как было предложено, drawText принимает любые CharSequence , что означает, что мы можем сделать нашу собственную интеллектуальную реализацию:

final class PrefixedInt implements CharSequence {

    private final int prefixLen;
    private final StringBuilder buf;
    private int value; 

    public PrefixedInt(String prefix) {
        this.prefixLen = prefix.length();
        this.buf = new StringBuilder(prefix);
    }

    private boolean hasValue(){
        return buf.length() > prefixLen;
    }

    public void setValue(int value){
        if (hasValue() && this.value == value) 
            return; // no change
        this.value = value;
        buf.setLength(prefixLen);
        buf.append(value);
    }


    // TODO: Implement all CharSequence methods (including 
    // toString() for prudence) by delegating to buf 

}

// Usage:
private final PrefixedInt scoreText = new PrefixedInt("Your score is: ");
...
scoreText.setValue(Score.points);
canvas.drawText(scoreText, 0, scoreText.length(), x, y, paint);

Теперь рисование счета не вызывает никаких выделений (кроме, может быть, одного или двух в начале, когда внутренний массив buf , возможно, придется увеличить, и все, что drawText , может быть увеличено до ).

4
ответ дан 24 November 2019 в 16:26
поделиться

В ситуации, когда критически важно избегать пауз сборщика мусора, вы можете использовать один трюк, чтобы намеренно запустить сборщик мусора в момент, когда вы знаете, что пауза не неважно.Например, если в конце игры используется функция showScores с интенсивным использованием мусора, пользователя не будет слишком отвлекать дополнительная задержка в 200 мс между отображением экрана счета и началом следующей игры ... так что вы можете позвонить System.gc () после закрашивания экрана результатов.

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

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

3
ответ дан 24 November 2019 в 16:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: