1 / 14

Minimising memory churn

With examples in C#. Minimising memory churn. by Christopher Myburgh Technical Director at Team Devil Games www.teamdevil.com. stack memory & heap memory. Heap Objects have an indeterminate lifetime.

ramirezh
Télécharger la présentation

Minimising memory churn

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. With examples in C# Minimising memory churn by Christopher Myburgh Technical Director at Team Devil Games www.teamdevil.com

  2. stack memory & heap memory • Heap • Objects have an indeterminate lifetime. • In managed environments, a “garbage collector” must periodically run to free memory from unreferenced objects. • The heap becomes fragmented as objects are destroyed. A severely fragmented heap might cause allocations to take longer. • Stack • Objects are always destroyed in the opposite order that they are created. • Every thread has its own stack.

  3. “mark-and-sweep” garbage collector basics • Traverses the object graph starting from static variables and the stack(s). • Tags all the heap objects it encounters. • All heap objects that remain untagged when traversal is completed are then destroyed, and the memory that they occupied is made available for re-use.

  4. Memory churn • Is the rate of creation and destruction of objects in heap memory. • The higher the churn, the more severely the heap could become fragmented, the more often the garbage collector might be triggered and the more work the garbage collector may have to do. • A tell-tale sign of severe memory churn in games is small but regular pauses in gameplay, caused by the garbage collector running very frequently and taking exceedingly long to complete (1 or more entire frames). • Severe memory churn is caused by repeatedly creating heap objects with very short lifetimes.

  5. Best practices to minimise memory churn classFoo { void DoSomething() { // ... } } • Avoid creating heap objects inside loops that are forgotten at the end of each iteration. void DoStuff(int count) { // allocated outside the loop Foo myHeapObject = newFoo(); for (int i = 0; i < count; ++i) { myHeapObject.DoSomething(); } } void DoStuff(int count) { for (int i = 0; i < count; ++i) { // allocated within the loop Foo myHeapObject = newFoo(); myHeapObject.DoSomething(); } }

  6. Best practices to minimise memory churn classFoo { void DoSomething() { // ... } } • Avoid creating heap objects during every update that are forgotten at the end of the update. classMyScript { // allocated before any updates Foo myHeapObject = newFoo(); void Update() { myHeapObject.DoSomething(); } } classMyScript { void Update() { // allocated during the update Foo myHeapObject = newFoo(); myHeapObject.DoSomething(); } }

  7. Best practices to minimise memory churn classProjectile { void Enable() { // ... } void Disable() { // ... } } classProjectileManager { Queue<Projectile> projectilePool = newQueue<Projectile>(); Projectile CreateProjectile() { Projectile projectile; // Get an unused projectile from the pool, // or create a new one if there are none spare. if (projectilePool.Count > 0) projectile = projectilePool.Dequeue(); else projectile = newProjectile(); projectile.Enable(); return projectile; } void DestroyProjectile(Projectile projectile) { // Return the unused projectile to the pool. projectile.Disable(); projectilePool.Enqueue(projectile); } } • Pool game objects that occur frequently (eg. projectiles in a shoot-em-up).

  8. reference types & value types in C# • Reference types • Objects are always allocated on the heap. • Include classes, interfaces, arrays and delegates. • Value types • Objects are allocated on the stack when declared as local variables or as method parameters, or form part of the object on the heap when declared as class members or as the element type of an array. • Include enums and structs.

  9. Implicit heap allocations in C# • string concatenationclassPlayer{publicstring Name;publicint Score;}// ...// ToString() is called on player.Score and concatenations generate new stringsstring hudText = "Name: " + player.Name + "; Score = " + player.Score; • boxingint num = 0;object numObj = num; // creates a copy of num on the heapinterfaceIMyInterface{ // …}structMyStruct : IMyInterface{ // …}MyStruct myStruct = newMyStruct();IMyInterface myInterface = myStruct; // creates a copy of myStruct on the heap

  10. Implicit heap allocations in C# • delegate creationbool LessThanZero(int x){return x < 0;}List<int> myList = newList<int>();// …// The first statement is just shorthand for the second.myList.RemoveAll(LessThanZero);myList.RemoveAll(newPredicate<int>(LessThanZero)); • lambda expressionsList<int> myList = newList<int>();// …// A delegate is allocated for an anonymous method.myList.RemoveAll(x => x < 0);// Captured variables are implemented as members of an anonymous class which must also be allocated.int j = 0;myList.RemoveAll(x => x < j);

  11. Implicit heap allocations in C# • delegate chainingvoid DoSomething1(){// …}void DoSomething2(){// …}void DoSomething3(){// …}Action action1 = DoSomething1;Action action2 = DoSomething2;// New delegates are allocated when chained.// By default, events are implemented by chaining delegates.Action actionAll = action1 + action2;actionAll += DoSomething3;

  12. Implicit heap allocations in C# • foreach loops (in many but not all cases)foreach (T item in myEnumerableObject){// …}// The above foreach loop is shorthand for the loop below, so check the return type of GetEnumerator().// If the return type is a struct, the enumerator is allocated on the stack.// If the return type is a class, the enumerator is allocated on the heap.// If the return type is an interface, either a class is allocated on the heap or a struct is boxed.using (var anonymousEnumerator = myEnumerableObject.GetEnumerator()){while (anonymousEnumerator.MoveNext()) {T item = (T)anonymousEnumerator.Current; // read-only// …}}

  13. Implicit heap allocations in C# • params method argumentsint AddAll(paramsint[] nums){// …}int num1 = 1, num2 = 2, num3 = 3;int sum;// The first statement is just shorthand for the second.sum = AddAll(num1, num2, num3);sum = AddAll(newint[] { num1, num2, num3 }); • passing strings from an unmanaged context to a managed context

  14. 'k thanks bye.

More Related