the gamedesigninitiative at cornell university

Lecture 13

Memory in C++ Sizing Up Memory

Primitive Data Types Complex Data Types

— byte: basic value (8 bits) — Pointer: platform dependent — 4 bytes on 32 bit machine — char: 1 byte — 8 bytes on 64 bit machine — short: 2 bytes — Java reference is a pointer — int: 4 bytes — Array: data size * length Not standard — long: 8 bytes May change — Strings same (w/ trailing null) — Struct: sum of fields — float: 4 bytes IEEE standard — Same rule for classes Won’t change — double: 8 bytes — Structs = classes w/o methods

the gamedesigninitiative 2 Memory in C++ at cornell university Memory Example

class Date { short year; 2 byte byte day; 1 byte byte month; 1 bytes } 4 bytes class Student { int id; 4 bytes Date birthdate; 4 bytes Student* roommate; 4 or 8 bytes (32 or 64 bit) } 12 or 16 bytes

the gamedesigninitiative 3 Memory in C++ at cornell university Memory and Pointer Casting

— C++ allows ANY cast // Floats for OpenGL — Is not “strongly typed” float[] lineseg = {0.0f, 0.0f, 2.0f, 1.0f}; — Assumes you know best — But must be explicit cast // Points for calculation Vec2* points — Safe = aligns properly // Convert to the other type — Type should be same size points = (Vec2*)lineseg; — Or if array, multiple of size for(int ii = 0; ii < 2; ii++) { — Unsafe = data corruption CULog("Point %4.2, %4.2", — It is all your fault points[ii].x, points[ii].y); — Large cause of seg faults }

the gamedesigninitiative 4 Memory in C++ at cornell university Two Main Concerns with Memory

— Allocating Memory — With OS support: standard allocation —Reserved memory: memory pools

— Getting rid of memory you no longer want — Doing it yourself: deallocation — Runtime support: garbage collection

the gamedesigninitiative 5 Memory in C++ at cornell university C/C++: Allocation Process

malloc new

— Based on memory size — Based on data type — Give it number of bytes — Give it a data type — Typecast result to assign it — If a class, calls constructor — No initialization at all — Else no default initialization — Example: — Example: char* p = (char*)malloc(4) Point* p = new Point(); Stack Heap Stack Heap sizeof

? n bytes 1

? 0 (Class) … … ? 1

the gamedesigninitiative 6 Memory in C++ at cornell university C/C++: Allocation Process

malloc new

— Based on memory size — Based on data type — Give it number of bytes — Give it a data type — Typecast result to assign it — If a class, calls constructor — No initialization at all — Else no default initialization Preferred in C Preferred in C++ — Example: — Example: char* p = (char*)malloc(4) Point* p = new Point(); Stack Heap Stack Heap sizeof

? n bytes 1

? 0 (Class) … … ? 1

the gamedesigninitiative 7 Memory in C++ at cornell university Custom Allocators

Pre-allocated Array (called Object Pool)

Start Free End

— Idea: Instead of new, get object from array — Just reassign all of the fields — Use Factory pattern for constructor Easy if only — See alloc() method in CUGL objects one object — Problem: Running out of objects type to — We want to reuse the older objects allocate — Easy if deletion is FIFO, but often isn’t

the gamedesigninitiative 8 Memory in C++ at cornell university Custom Allocators in CUGL class Texture : : public enable_shared_from_this { public: /** Creates a sprite with an image filename. */ static shared_ptr allocWithFile(const string& file); Allocation & initialization /** Creates a sprite with a Texture2D object. */ static shared_ptr< Texture> allocWithData(const void *data, int w, int h); private: /** Creates, but does not initialize sprite */ Allocation Texture(); only

/** Initializes a sprite with an image filename. */ virtual bool initWithFile(const string& file); Initialization /** Initializes a sprite with a texture. */ only virtual bool initWithData(const void *data, int w, int h); };

the gamedesigninitiative 9 Memory in C++ at cornell university Custom Allocators in CUGL class Texture : : public enable_shared_from_this { public: /** Creates a sprite with an image filename. */ static shared_ptr allocWithFile(const string& file); Allocation & initialization /** CreatesCustomizable a sprite with a Texture2D allocation object. */ static shared_ptr< Texture> allocWithData(const void *data, int w, int h); private: /** Creates, but does not initialize sprite */ Allocation Sprite(); Standard allocation only

/** Initializes a sprite with an image filename. */ virtual bool initWithFile(const string& file); Initialization /** Initializes a sprite with a texture. */ only virtual bool initWithData(const void *data, int w, int h); };

the gamedesigninitiative 10 Memory in C++ at cornell university Free Lists

— Create an object queue // Free the new particle — Separate from preallocation freelist.push_back(p); — Stores objects when “freed” … — To allocate an object… // Allocate a new particle — Look at front of free list Particle* q; — If object there take it if (!freelist.isEmpty()) { — Otherwise make new object q = freelist.pop(); — Preallocation unnecessary } else { — Queue wins in long term q = new Particle(); — Main performance hit is } deletion/fragmentation q.set(…)

the gamedesigninitiative 11 Memory in C++ at cornell university Particle Pool Example

the gamedesigninitiative 12 Memory in C++ at cornell university Particle Pool Example

See FreeList and GreedyFreeList

the gamedesigninitiative 13 Memory in C++ at cornell university Two Main Concerns with Memory

— Allocating Memory — With OS support: standard allocation —Reserved memory: memory pools

— Getting rid of memory you no longer want — Doing it yourself: deallocation — Runtime support: garbage collection

the gamedesigninitiative 14 Memory in C++ at cornell university Manual Deletion in C/C++

— Depends on allocation int main() { — malloc: free cout << "Program started" << endl; int* a = new int[LENGTH]; — new: delete

— What does deletion do? delete a; — Marks memory as available for(int ii = 0; ii < LENGTH; ii++) { — Does not erase contents cout << "a[" << ii << "]=" — Does not reset pointer << a[ii] << endl; — Only crashes if pointer bad } — Pointer is currently NULL cout << "Program done" << endl; — Pointer is illegal address }

the gamedesigninitiative 15 Memory in C++ at cornell university Recall: Allocation and Deallocation

Not An Array Arrays

— Basic format: — Basic format: type* var = new type(params); type* var = new type[size]; … … delete var; delete[] var; // Different — Example: — Example: — int* x = new int(4); — int* array = new int[5]; — Point* p = new Point(1,2,3); — Point* p = new Point[7]; — One you use the most — Forget [] ==

the gamedesigninitiative 16 C++ Overview at cornell university Memory Leaks

— Leak: Cannot release memory — Object allocated on heap — Only reference is moved — Consumes memory fast!

— Can even happen in Java memoryArea = newArea; — JNI supports native libraries — Method may allocate memory — Need another method to free — Example: dispose() in JOGL

the gamedesigninitiative 17 Memory in C++ at cornell university A Question of Ownership void foo() { void foo(int key) { MyObject* o = MyObject* o = new MyObject(); table.get(key); o.doSomething(); o.doSomething(); o = null; o = null; Memory Not a return; Leak return; Leak } }

the gamedesigninitiative 18 Memory in C++ at cornell university A Question of Ownership void foo() { void foo(int key) { MyObject* o = MyObject* o = table.get(key); table.get(key); table.remove(key); table.remove(key); ntable.put(key,o); o = null; Memory o = null; Leak? return; Not a return; Leak } }

the gamedesigninitiative 19 Memory in C++ at cornell university A Question of Ownership

Thread 1 Thread 2

“Owners” of obj

void run() { void run() { o.doSomething1(); o.doSomething2(); } }

Who deletes obj?

the gamedesigninitiative 20 Memory in C++ at cornell university Understanding Ownership

Function-Based Object-Based

— Object owned by a function — Owned by another object — Function allocated object — Referenced by a field — Can delete when function done — Stored in a data structure — Ownership never transferred — Allows multiple ownership — No guaranteed relationship — May pass to other functions between owning objects — But always returns to owner — Call each owner a reference — Really a stack-based object — When can we deallocate? — Active as long as allocator is — No more references — But allocated on heap (why?) — References “unimportant”

the gamedesigninitiative 21 Memory in C++ at cornell university Understanding Ownership

Function-Based Object-Based

— Object owned by a function — Owned by another object — Function allocated object — Referenced by a field — Can delete when function done — Stored in a data structure — Ownership never transferred — Allows multiple ownership — No guaranteed relationship — MayEasy pass: to Will other ignorefunctions between owning objects — But always returns to owner — Call each owner a reference — Really a stack-based object — When can we deallocate? — Active as long as allocator is — No more references — But allocated on heap (why?) — References “unimportant”

the gamedesigninitiative 22 Memory in C++ at cornell university Reference Strength

Strong Reference

— Reference asserts ownership — Reference != ownership — Cannot delete referred object — Object can be deleted anytime — Assign to NULL to release — Often for performance caching — Else assign to another object — Only use indirect references — Can use reference directly — Copy to local variable first — Compute on local variable — No need to copy reference — Treat like a normal object — Be prepared for NULL — Reconstruct the object? — Standard type of reference — Abort the computation?

the gamedesigninitiative 23 Memory in C++ at cornell university C++11 Support: Shared Pointers

— C++ can override anything — Assignment operator = handle — Dereference operator -> — Use special object as pointer — Has field to reference object object — Tracks ownership of object — Uses Foo* object = new Foo(); — What about deletion? shared_ptr handle(object); — Smart pointer is on stack … — Stack releases ownership handle->foo(); //object->foo()

the gamedesigninitiative 24 Memory in C++ at cornell university C++11 Support: Shared Pointers

void foo() { shared_ptr p1(new Thing); // Allocate new object shared_ptr p2=p1; // p1 and p2 share ownership shared_ptr p3(new Thing); // Allocate another Thing … p1 = find_some_thing(); // p1 might be new thing p3->defrangulate(); // call a member function cout <<*p2 << endl; // dereference pointer … // "Free" the memory for pointer p1.reset(); // decrement reference, delete if last p2 = nullptr; // empty pointer and decrement }

the gamedesigninitiative 25 Memory in C++ at cornell university C++11 Support: Weak Pointers

void foo() { shared_ptr p1(new Thing); // Allocate new object weak_ptr p2=p1; // p2 is a weak reference … p1 = find_some_thing(); // p1 might be new thing auto p3 = p2.lock(); // Must lock p2 to dereference cout <<*p3 << endl; // dereference pointer … // "Free" the memory for pointer p1.reset(); // decrement reference, delete if last p2 = nullptr; // empty pointer (but does not decrement) }

the gamedesigninitiative 26 Memory in C++ at cornell university Passing Smart Pointers

— Shared pointers are objs void foo(shared_ptr a) { // Creates new reference to a — They are not the pointer } — They contain the pointer — Copy increases reference void foo(shared_ptr& a) { // No new reference to a — What to avoid if possible // But can modify pointer — So reference smart pointer } — But make reference const void foo(const shared_ptr& a){ — Keep from modifying ptr // The preferred solution — Can still modify object }

the gamedesigninitiative 27 Memory in C++ at cornell university Summary

— Memory usage is always an issue in games — Uncompressed images are quite large — Particularly a problem on mobile devices — Limit allocations in your animation frames — Intra-frame objects: cached objects — Inter-frame objects: free lists — Must track ownership of allocated objects — The owner is responsible for deletion — C++11 smart pointers can manage this for us

the gamedesigninitiative 28 Memory in C++ at cornell university