Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Understanding vtable And Unity’s Memory Layout

Understanding vtable And Unity’s Memory Layout

Many developers think about memory when developing with Unity.
In this slide, I will focus on memory and explain how memory is laid out in Unity and how dynamic polymorphism is achieved.
I will use diagrams to make it as easy to understand as possible.

Kutani Mio

July 02, 2023
Tweet

More Decks by Kutani Mio

Other Decks in Programming

Transcript

  1. Introduce myself ABOUT ME I'm working as a lead game

    engineer who loves Eevee at a game company. Recently, I've been doing lots of recruiting and management. 
 My side job is mainly Metaverse/ game projects. Rossam Experience Unity C# about 5 yrs (2D and 3D) Unreal Engine C++ about 2 yrs Jenkins I was an MVP of Microsoft from 2018.3 to 2022.3
  2. Contents ✦ About Unity’s memory - What type of memory

    is in Unity? - Stack and Heap ✦ Basic of Memory layout ✦ Offset - Offset when using inheritance ✦ About vtable - Overview - Disadvantages
  3. Used on the C# side. This memory layer is automatically

    managed for memory allocation and release by the OS, Mono, or IL2CPP. Managed memory Memory type About Unity’s memory Used on the C# side. This memory layer is used when using JobSystem or Burst. Use Memory allocation and release at your own risk. C# unmanaged memory Used on the Unity side. C++ uses this memory layer for running Unity. Unity Engineers don’t use it much. Native memory
  4. Let’s focus on 
 Managed Memory! Memory type About Unity’s

    memory Managed memory Used on the C# side. This memory layer is automatically managed for memory allocation and release by the OS, Mono, or IL2CPP. Used on the C# side. This memory layer is used when using JobSystem or Burst. Use Memory allocation and release at your own risk. C# unmanaged memory Used on the Unity side. C++ uses this memory layer for running Unity. Unity Engineers don’t use it much. Native memory
  5. This memory is used when using code to generate code.

    We are usually not aware of it. There are three types of managed memory stored in RAM. Stack Heap Native VM 
 Memory (Managed Heap) It’s a small memory managed by the OS. This memory is allocated during the initialization phase of the app and can’t be resized. Memory type About Unity’s memory It’s a memory managed by Mono or IL2CPP. The size of this memory is changed during the running of the application.
  6. Stack Variables of a value type defined from other than

    a reference type Struct / Enum types Addresses of objects in Heap Arrays allocated by stackalloc Variables of reference type 
 (array, class, delegate, object, string, etc..) Boxed value type objects Captured variables in anonymous functions include lambda expressions static variables Heap (Managed Heap) Developer mainly uses the Stack and Heap. The following types are saved on these stored; About Unity’s memory Stack & Heap
  7. Advantages and disadvantages of Stack Stack Access to data in

    memory is fast. Strict memory management on the OS side prevents memory fragmentation. 
 An exception occurs if a variable contains a value outside the type range. Since the stack’s memory is small, an exception occurs when it is used up. void Main() { int a; int b = 4; int c = b; } int a; int b; int c; void Main() { int a; int b = 4; int c = b; int d = 0; } int a; int b; int c; int d; before after +1 About Unity’s memory Stack & Heap
  8. Flexible and can be used as needed. Automatic management by

    GC minimizes memory corruption and errors. Since the GC side doesn’t go so far as to tidy up the used memory, fragmentation occurs. Access to data in memory is slow. Heap (Managed Heap) class A object B array D string E Example of memory fragmentation string (released) array(released) object F (released) object F (released) Data of the size of object F or smaller can be stored here About Unity’s memory Stack & Heap Advantages and disadvantages of Heap
  9. Offset Basic of Memory layout Memory for the class is

    allocated on the Heap. Variables of reference type 
 (array, class, delegate, object, string, etc..) Boxed value type objects Captured variables in anonymous functions include lambda expressions static variables Heap (Managed Heap)
  10. When a group of class variables of type int is

    defined and instantiated (memory layout order is not considered ) public class Hoge { public int a; public int b; public int c; } Instance of class Hoge int c; int b; int a; +0x08 +0x04 +0x00 Distance from 
 first address (offset) Offset Basic of Memory layout
  11. Inheritance Offset In the case of Class C with simple

    inheritance, the address of a group of functions is calculated at compile time & link time. 
 The memory allocation configuration of a Class C instance will look like the following; public class A { public void HogeA() { … } } public class B : A { public void HogeB() { … } } public class C : B { public void HogeC() { … } } Class C Object Contents of Class C Contents of Class B Contents of Class A this Basic of Memory layout The pointer initially points to the beginning.
  12. When calling HogeB() implemented in class B from an object

    of class C, it is necessary to move ‘this’ pointer to the object part of B to get the pointer for class B. To do so, the pointer is moved by referencing the offset for class B that class C has. this + Offset for B First address of C void Main() { var C = new C(); c.HogeB(); } Inheritance Offset Basic of Memory layout Class C Object Contents of Class C Contents of Class B Contents of Class A
  13. Overview About vtable Type-dependent function calls are resolved using "virtual

    method table(vtable)”. This is a collection of pointers to virtual functions related to the target class. If the class has at least one virtual method, a unique vtable is created for each class. public class Base { public virtual int GetId() { … } } public class A : Base { public override int GetId() { … } } public class B : A { public new int GetId() { … } } Object of class Base Class Base information vtable for class Base Object of class A Class Base and A information vtable for class A Object of class B Class Base, A, and B information vtable for class B
  14. public class Base { public virtual int GetId() { …

    } } public class A : Base { public override int GetId() { … } } public class B : A { public new int GetId() { … } } For example, looking at the table information for class B, the function pointer of the A side with override GetId() and the function pointer of GetId() redefined for class B with new are stored, The function pointer of GetId(), which is redefined for class B with new, is stored in the table. Objects of class B Class Base, A, and B information vtable for class B A:GetId() B:GetId() vtable example About vtable
  15. Disadvantages Instances of the virtual function holding class have a

    pointer to access the vtable is implicitly added to the top of the class. Because of it, the class’s size will be slightly larger. Increase instance size There is a slight performance loss because virtual function calls are made via vtable. This is very small, but the overhead can quickly add up if thousands of calls are made per frame. Performance loss Even if performance is impaired by the use of virtual functions, it is difficult to pinpoint the cause. It is necessary to use them with risk in mind from the beginning. Profiling difficulty About vtable
  16. References C++ͰֶͿʂϝϞϦϨΠΞ΢τͱvtableͷ͢ʍΊ ʙಈతϙϦϞϑΟζϜΛ࣮ݱ͢Δ࢓૊Έʙ Unity ύϑΥʔϚϯενϡʔχϯά όΠϒϧ Memory Management in Unity

    Unity 2021 LTSͰϝϞϦͷ࢖͍ํΛΧελϚΠζ͢Δ Unity ͷϝϞϦʢެࣜϦϑΝϨϯεʣ ʲUnityʳUnsafeUtilityʹ͍ͭͯవΊͯΈΔ UnityͷGC͸ͲΜͳ࣮૷ʹͳ͍ͬͯΔͷ͔ VIRTUAL, NEW AND OVERRIDE IN C# [ࡶه]ଟॏܧঝͰ͖ͳ͍ཧ༝ ήʔϜΤϯδϯΞʔΩςΫνϟ ୈ3൛