Slide 1

Slide 1 text

Understanding vtable And Unity’s Memory Layout 
 Rossam (Mio Kutani) Mechanisms for Polymorphism in Unity

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Original Article of this slide https://qiita.com/4_mio_11/items/ aa71f18b24ab55e4cb3d

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

About Unity’s memory

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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.

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Basic of Memory layout

Slide 13

Slide 13 text

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)

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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.

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

About vtable

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

References C++ͰֶͿʂϝϞϦϨΠΞ΢τͱvtableͷ͢ʍΊ ʙಈతϙϦϞϑΟζϜΛ࣮ݱ͢Δ࢓૊Έʙ Unity ύϑΥʔϚϯενϡʔχϯά όΠϒϧ Memory Management in Unity Unity 2021 LTSͰϝϞϦͷ࢖͍ํΛΧελϚΠζ͢Δ Unity ͷϝϞϦʢެࣜϦϑΝϨϯεʣ ʲUnityʳUnsafeUtilityʹ͍ͭͯవΊͯΈΔ UnityͷGC͸ͲΜͳ࣮૷ʹͳ͍ͬͯΔͷ͔ VIRTUAL, NEW AND OVERRIDE IN C# [ࡶه]ଟॏܧঝͰ͖ͳ͍ཧ༝ ήʔϜΤϯδϯΞʔΩςΫνϟ ୈ3൛

Slide 22

Slide 22 text

Thank you for reading!