Schemi di allocazione della memoria utilizzati nello sviluppo del gioco


20

Ho cercato di creare i miei metodi di allocazione (che supporteranno cose come un pool di memoria e la creazione di profili), tuttavia, mentre continuo la mia ricerca ho cercato di come è stato fatto nello sviluppo del gioco.

Quale tecnica di allocazione della memoria potrei usare e perché è una buona tecnica?


1
ne hai davvero bisogno? è solo una delle cose più complicate che una squadra possa implementare, se può implementarla.
Ali1S232

4
Per me è un campo di interesse, quindi vorrei conoscerlo e attuarlo
chadb,

Devo dire che l'argomento è davvero interessante ... Ci sono casi in cui ciò può significare assegnare, ma sul tuo gioco per PC medio preferirei preoccuparmi del gioco reale ...
rioki

Hai cercato il codice sorgente per la moderna libreria standard malloc e gratuito o nuovo ed elimina? Chiedo perché sembra che fornirebbe una base molto utile con cui confrontare eventuali strategie di allocazione alternative con algoritmicamente o praticamente. Sembra che fornirebbe anche una visione reale di ciò in cui ti troverai.
Louis Langholtz,

Risposte:


25

L'architettura di Game Engine contiene alcune informazioni su questo argomento. Le basi sono che è necessario fare alcune analisi per capire quali sono i requisiti di memoria per livello / frame / ecc. sono simili, ma ci sono alcuni schemi che l'autore menziona aver visto più volte:

  • Allocatori basati su stack: assegnano una volta un ampio segmento di memoria, quindi allocano i puntatori all'interno di quel blocco di memoria in risposta alle richieste da altre parti del gioco. Ciò è utile per evitare i cambi di contesto richiesti dall'allocazione della memoria e anche perché è possibile utilizzare le proprie tecniche per applicare la contiguità o l'allineamento specifico per le operazioni SIMD. Alcuni motori usano anche uno stack a doppia estremità in cui un tipo di risorsa viene caricato dall'alto e l'altro viene caricato dal basso. Forse LSR (Load and Stay Resident, il tipo di cose che saranno necessarie per tutta la durata del gioco) dall'alto e dati per livello dal basso.
  • Memoria a frame singolo o memoria a doppio buffer: memoria per operazioni che si verificano entro uno o due cicli di frame. Questo è utile perché invece di dover allocare / deallocare ogni frame, puoi semplicemente spazzare via i dati dell'ultimo frame reimpostando il puntatore che usi per tenere traccia della memoria all'inizio del blocco.
  • Pool di oggetti: un blocco di memoria per molti oggetti della stessa dimensione, come particelle, nemici, proiettili. Questi sono utili perché puoi facilmente raggiungere la contiguità trovando il primo segmento inutilizzato nel tuo pool. Inoltre semplificano l'iterazione, poiché ogni oggetto ha un offset noto rispetto all'ultimo.

La cosa più grande che l'autore menziona a cercare è la frammentazione della memoria. Questo è meno un problema se si sta sviluppando, ad esempio, un PC in cui si dispone di un tipo di backup di paging della memoria su cui si può contare, ma in un contesto di memoria fissa come una console, c'è il rischio di essere "memoria insufficiente" quando si tenta di allocare un oggetto di grandi dimensioni perché la memoria è frammentata in modo tale da rendere disponibili solo piccoli blocchi contigui. A tal fine, raccomanda che un allocatore basato su stack come sopra includa anche un metodo per deframmentare periodicamente il suo contenuto.

Per ulteriori informazioni sul codice reale coinvolto in questo, consiglio vivamente l'articolo di Christian Gyrling, "Siamo fuori memoria?" , che copre le tecniche per gli allocatori personalizzati, principalmente dal punto di vista dell'analisi dei modelli di utilizzo della memoria, ma ciò è applicabile anche all'elaborazione di una soluzione personalizzata per la gestione della memoria.


1

Da quello che ho visto (ma non fatto) ogni gioco tende a ereditare i meccanismi di allocazione da un framework, da un motore di gioco, dalla versione precedente (2010 -> 2011) o ottiene una serie di nuovi scritti appositamente per i suoi struttura (quando le strutture dati sono riutilizzabili e di dimensioni fisse o di numerosi tipi e dimensioni variabili).

Inoltre abbiamo avuto allocatori diversi per file audio / componenti rispetto a livelli e altri oggetti di gioco nello stesso progetto. In altri progetti gli allocatori sono ereditati da librerie esterne solo per i componenti gestiti da quella lib.

L'ottimizzazione dipende davvero dalle tue esigenze. Ma di solito l'allocazione viene eseguita prima di entrare nella scena di gioco e quindi la memoria viene riutilizzata. Alcuni giochi possono cavarsela senza assegnare allocatori personalizzati. Ma per i giochi d'azione in cui il processore, la memoria e le risorse di dati sono preventivati, non puoi permetterti di perdere tempo di elaborazione su grandi allocazioni, non puoi sprecare memoria a frammentazione e altri problemi.

Per quanto riguarda gli esempi, dovresti semplicemente dare un'occhiata al motore di gioco OGRE 3D che ha alcune opzioni per configurare gli allocatori di memoria.


0

L'errore che viene spesso commesso è quello di scrivere i propri allocatori in modo da poter avere un maggiore controllo sulla quantità di memoria utilizzata da ciascun sistema e avere più visibilità su ciò che sta accadendo. Un modo molto migliore per raggiungere questo obiettivo è utilizzare un profiler di memoria. Esistono molti profiler di memoria, il mio profiler MemPro ne è un esempio. Questo è un modo totalmente non invasivo per tenere traccia di tutto l'utilizzo della memoria e puoi dividerlo automaticamente in sottosistemi usando i filtri jolly callstack. Idealmente è meglio mantenere l'allocazione e il tracciamento della memoria completamente separati, hanno requisiti totalmente diversi.

Dividere arbitrariamente la memoria in pool può spesso essere dannoso perché ogni pool avrà un sovraccarico. Puoi finire per usare molta più memoria di quella di cui hai bisogno senza accorgertene. Per ridurre gli sprechi è sempre meglio raggruppare tutto insieme, il gioco viene quindi condiviso da tutto il sistema.

Le uniche ragioni per utilizzare allocatori personalizzati sono le prestazioni della CPU (principalmente per la coerenza della cache) e per limitare la frammentazione. Un esempio perfetto di ciò è un sistema di particelle. Volete tutte le particelle contigue nella memoria e non volete riempire la memoria principale con molte allocazioni di breve durata. Un altro buon esempio di partizionamento è un linguaggio di scripting.

Se vuoi un esempio di sostituzione di malloc per scopi generici, puoi dare un'occhiata al mio allocatore VMem . È stato utilizzato in numerosi giochi AAA spediti. Ha tecniche che limitano la frammentazione e mantengono basso il footprint di memoria, qualcosa di fondamentale per i giochi per console. È anche molto veloce in contese con thread elevati. Il mio sito Web ha un'ampia documentazione su queste tecniche.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.