2017-01-19 15 views
1

Я разрабатываю симуляцию в Scala внутри игры. Я бы хотел использовать только неизменные объекты для определения логики игры, даже если она неэффективна. Зачем? Потому что я могу, так и сделаю.Обработка тяжелой нагрузки на GC с помощью классов Scala Case

Теперь я немного подчеркиваю основной игровой цикл с толканием имитации с огромной нагрузкой. В основном у меня есть эти вложенные классы case, и я работаю с .copy(), чтобы определить следующее состояние данного объекта внутри моделирования. Проблема в том, что все эти операции генерируют много объектов без ссылок, поэтому в конце каждого шага я запускаю полный GC. Это плохо для игровых представлений.

Итак, я начал агрессивную оптимизацию: прежде всего теперь шаг за шагом запускается параллельно за игрой, вычисляя «следующее состояние», которое в основном охватывает день в игре. Таким образом, игроку будет показано состояние с текущего дня, в то время как следующий будет вычисляться. Это работает, потому что в основном каждый крупный субъект в игре (города, в основном) предполагается эволюционировать изолированно. Если какой-либо агент (игрок или другой агент AI, путешествующий между городами) свяжется с городом, я буду пересчитывать «следующее состояние» в соответствии с действиями агента. В любом случае это не имеет значения.

Итак, у меня есть эти параллельные сущности, развивающиеся за сценой, и когда закончился день (день определяется как 5 шагов игрока на карте мира) Я использую Await.result(nextWorldState, 5 seconds) в качестве точки rendez-vous для обновления текущего состояния моделирования. Это не обязательно, как игра должна работать, но я хочу проверить точку rendez-vous, когда остальная часть игры ждет вычисления следующего состояния, потому что это, вероятно, будет необходимо.

Проблема заключается в том, что после этого я разыменовываю множество объектов сразу, и это вызывает сбор GC. Я пробовал некоторые решения, но всегда есть момент, когда я получаю доступ к результату Будущего и заменяю его текущим состоянием, и это всегда вызывает GC.

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

Вот некоторые из них не столь псевдокод от фактической функции, что справиться с этой логикой:

class WorldSimulationManager(var worldState: WorldState) { 

    private var nextWorldState: Future[WorldState] = 
    Future.successful(worldState) 


    def doImmutableStep(gameMap:GameMap,movedCountToday:Int):Unit = { 

    nextWorldState = 
     nextWorldState.flatMap(_.doStep(gameMap)) 

    if (movedCountToday >= Constants.tileMovementsToDay) { 
     worldState = Await.result(nextWorldState, 5 seconds) 

    } 
    } 

} 

ответ

2

Чтобы уменьшить боль от Full GC Я предлагаю использовать G1 или CMS, а не параллельно коллектору, и increaing молодое пространство, чтобы уменьшить количество объектов, продвигаемых в пространство, но ничто не сравнится с созданием меньше работы в первую очередь.

Чем больше вы создаете мусор, тем больше работы вы выполняете и тем больше усилий, которые должен выполнить gc для очистки объектов. Создание объектов быстрее с большим количеством процессоров не сделает GC менее болезненным.

+0

На самом деле создание множества недолговечных неизменяемых объектов в значительной степени является лучшим случаем для современных поколений GC. Еще 10 лет назад GC GC Azul продемонстрировал вспашку через 20 GiByte/s мусора, созданного 700 параллельными нитями на 864-ядерной машине, даже не разбив пота, используя симуляцию Rich Hickey's Ant в Clojure. Современные GC поколения основаны на гипотезе поколений: объекты умирают молодыми, старые объекты не ссылаются на молодые объекты. Это именно то, что делает FP: много короткоживущих объектов, нет ссылок «назад вовремя». И никаких мутаторов. –

+0

@ JörgWMittag 25 МБ/с/ядро ​​было много для этой машины, но теперь вы получаете машины, производящие 1 ГБ/с/ядро. Тем не менее, самый простой способ настроить gc - это снизить нагрузку. –

+1

Ясно, что я буду работать над ограничением количества созданных объектов, но теперь я просто хочу оценить жизнеспособность этого подхода при тяжелых нагрузках. Во всяком случае, я попробовал CMS, и я просмотрел некоторые наблюдения, используя jstat.В результате существует лишь небольшая разница в частоте кадров между CMS и GC по умолчанию, и если нагрузка слишком велика, обе они не могут достичь удовлетворительных характеристик. Тем не менее я много узнал о GC (никогда не должен был оптимизировать его таким образом) и о моем коде. Дело в том, что пока я беру как текущее, так и следующее состояние в памяти, у меня возникнут проблемы. – Chobeat

 Смежные вопросы

  • Нет связанных вопросов^_^