необходимо ли использовать массивы для лучшего выравнивания памяти и использования кэша? - PullRequest
1 голос
/ 22 мая 2010

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

По сути, я обнаружил, что рекомендуется иметь хорошо выровненную память, особенно если вам нужен доступ к ним вместе.Например, в цикле.

Теперь, в моем проекте я работаю со своим диспетчером игровых объектов, и я подумывал иметь массив ссылок на GameObjects.Это означает, что у меня будет фактическая память моих объектов один за другим.

static const size_t MaxNumberGameObjects = 20;
GameObject mGameObjects[MaxNumberGameObjects];

Но, поскольку я буду реализовывать проект на основе компонентов, в котором игровые объекты будут иметь список компонентов (Mesh, RigidBody,Преобразование и т. Д.), Получу ли я вообще что-нибудь с массивом?

В любом случае, я видел, как некоторые люди просто использовали простой std :: map для хранения игровых объектов.Так что вы, ребята, думаете?

Мне лучше использовать чистую компонентную модель?

Ответы [ 2 ]

3 голосов
/ 22 мая 2010

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

Быстрые точки - сделайте ваши объекты хорошо вписанными в строки кэша и разделите «горячие» и «холодные» данные.

1 голос
/ 04 июня 2010

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

Что касается вопроса:

Я бы рекомендовал хранить каждый тип компонента в своих собственных пулах, где они будут храниться в смежных массивах. например:

ComponentPool<CollisionComponent> mCollisionComponents;
ComponentPool<MeshComponent> mMeshComponents;
...

Когда вы выделяете GameObject (он же извлекает его из пула), выделяйте определенные компоненты, необходимые для объекта.

Теперь вам следует избегать этого с компонентами:

void SomeCollisionWork() {
    for each object {
        if(object.hasCollisionComponent()) {
            DoCollisionWork(object.collisionComponent)
        }
    }
}

Вместо этого вы можете подойти к нему так:

void SomeCollisionWork() {
    for each allocated component in mCollisionComponents {
        DoCollisionWork(component)
    }
}

Если вы действительно нуждались в исходном GameObject (или других компонентах для этого объекта), вы можете хранить некоторые данные (например, индекс GameObject) в каждом компоненте. С помощью индекса объекта вы можете получить доступ к другим его компонентам в других ComponentPool s.

Какой смысл всего этого? Становится довольно легко разделить функциональность на отдельные части или «задания». Затем, если у вас есть компоненты, которые не зависят друг от друга, вы можете работать с ними параллельно (важно для «будущей» производительности).

Более подробно об этом я бы порекомендовал посмотреть на эту презентацию о динамической системе компонентов, разработанной Insomniac Games (обязательно прочитайте заметки докладчика): https://docs.google.com/present/edit?id=0ATIohmzo6z7TZGhjbmhidnFfMTg1MWNkcTJmcWZ4&hl=en

...