Está en la página 1de 37

3 VideoGame Programming

Memory management

Objetivos
Conocer los problemas asociados a la reserva de memoria en C++ Diferencias entre memoria esttica y dinmica A quin pertenece la memoria? Gestin de memoria en libreras Tcnicas para recoleccin de memoria automtica en C++ Recomendaciones y buenas prcticas

The memory leak

int main() { float *buffer = new float[1024]; ... ... ... return 0; }

The memory leak

int main() { while(...) { float *buffer = new float[1024]; } ... return 0; }

The memory leak


void func() { float *buffer = new float[1024]; fillBuffer(buffer); useBuffer(buffer); } int main() { while(...) { func(); } ... return 0; }

Stack vs Heap
Stack: Memoria esttica, se usa para las variables temporales de las funciones. Reserva/Libera de forma automtica. Heap: Memoria dinmica. Reserva/Libera de forma manual.

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Stack vs Heap

Problems
No liberar memoria dinmica (memory leak) Demasiadas llamadas recursivas (stack overflow) Usar un puntero a memoria previamente liberado Liberar dos veces la misma zona de memoria Sobrescribir memoria ...

Problems
No liberar memoria:

Problems
Llamadas recursivas

Problems
Usar un puntero a memoria previamente liberado Accedemos a memoria basura, pero el cdigo no es consciente de ello. El error puede que no se detecte en el momento No existe forma de asegurarse de que no pase.

Problems

Problems
Liberar dos veces la misma zona de memoria... Tambin se aplica a liberar una zona de memoria que no es la que inicialmente se reserv el programa termina

Problems
Sobrescribir memoria...

Solutions
Evitar a toda costa el uso de delete: Usar memoria esttica: Fijar un mximo de objetos, usar arrays de tamao predefinido y contar cuantos objetos hemos "instanciado" Ventaja: new es lento Desventajas: podemos quedarnos cortos podemos quedarnos muy largos hay que inicializar la memoria (no se usan constructores)

Solutions, static memory


static const uint32 kMaxGameObjects = 1024; static GameObject GameObjectArray[kMaxGameObjects]; static uint32 currentGameObjects = 0; GameObject* getGameObject() { uint32 index = findNextFreeGameObject(); initGameObject(index); return GameObjectArray+index; }

Solutions
Evitar a toda costa el uso de delete: Usar scoped_ptr y scoped_array scoped_xxx controla automticamente cuando se ha de liberar la memoria (cuando se sale del scope) Muy apropiado para atributos de instancia, buffers temporales, etc. Referencia: http://www.boost. org/doc/libs/1_47_0/libs/smart_ptr/scoped_pt r.htm http://www.boost. org/doc/libs/1_47_0/libs/smart_ptr/scoped_ar ray.htm

Solutions
Evitar a toda costa el uso de delete: Usar shared_ptr y shared_array Similares al scoped_xxx, pero incluyen un contador de referencias. Son ms difciles de usar, estamos forzados a pasar entre clases todo el shared_ptr/array Asegura que la memoria no se pierde y se libera cuando ya no hay ms referencias al bloque. Referencia: http://www.boost. org/doc/libs/1_47_0/libs/smart_ptr/shared_arr ay.htm http://www.boost. org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr .htm

Solutions
Evitar a toda costa el uso de delete: Usar Referenceds y ref_ptr Declaramos una clase base Referenced de la que heredar todo objeto a usar. El destructor lo declaramos virtual y protected, evitamos as que se puedan crear objetos en el Stack. Usamos ref_ptr cada vez que queramos guardar un link hacia el objeto. El objeto tendr un ref, y un unref, que no deberemos llamar manualmente (salvo alguna excepcin). Referencia: OSG, EDK, ...

Solutions, Referenced

Memory owner
void GameObject::set_name(const char *ptr);

Memory owner
void GameObject::set_name(const char *ptr); respecto a ptr: puede desaparecer (liberar) despus del set_name?La clase se copia el nombre? Debemos mantener el puntero externamente? la clase se copia el puntero, pero no duplica memoria? Si en vez de usar const char* usamos "char*" estamos transfiriendo la memoria?

Memory owner
La memoria tiene dueo Quien reserva la memoria tambin debe liberarla En una librera: Proveer de "init" y "destroy" para los objetos, de forma que tengamos control sobre la memoria que usa un objeto. Nunca obligar al usuario a liberar nuestra memoria. Con comentarios indicar qu propiedades debe cumplir la memoria que recibimos, o que devolvemos.

Memory owner
// Game object is a referenced instance, it must be hold // by a ref_ptr<GameObject>... GameObject *createGameObject(); // this is almost self explanatory shared_ptr<GameObject> createGameObject(); // receives a ptr to a uninitialized game object and // initializes it. void createGameObject(GameObject *g); void destroyGameObject(GameObject *g);

to summarize
Definir claramente quin es el propietario de la memoria ( el responsable de liberarla) No usar deletes, usar: scoped_ptr scoped_array ref_ptr shared_ptr shared_array La memoria reservada por el engine, debera ser liberada por el engine. Usar memoria esttica siempre que sea posible Proveer de funciones para inicializar, desinicializar los objetos si fuera necesario.

one more thing


Destruccin de jerarquas de clases: Nota: no usar herencia mltiple en C++, se puede, pero es altamente recomendable no usarlo. Los constructores se llaman primero a los ancestros. Los destructores, en orden inverso.

one more thing


Destruccin de jerarquas de clases: Nota: no usar herencia mltiple en C++, se puede, pero es altamente recomendable no usarlo. Los constructores se llaman primero a los ancestros. Los destructores, en orden inverso.

Cuidado con los destructores virtuales

Son ms necesarios de lo que parece.

virtual destructors

virtual destructors