๐ŸŽฎ Unity Study/Unity

[Unity Document Study] 1์ฃผ์ฐจ :: Unity Analysis - Memory in Unity

ibelieveinme 2024. 5. 1. 17:24
728x90

Unity ๋Š” Memory ์„ฑ๋Šฅ์„ ์œ„ํ•ด 3๊ฐ€์ง€ Memory ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

1. Managed memory: Heap ๊ณผ Garbage Collector ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ํ• ๋‹น&ํ•ด์ œ ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ

2. C# unmanaged memory: C# Collections package ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„ ๋ฐ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ.

3. Native memory: Unity Engine ์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” C++ ๋ฉ”๋ชจ๋ฆฌ. ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ Access ํ•  ์ˆ˜๋Š” ์—†์œผ๋‚˜ ์•Œ๊ณ ๋Š” ์žˆ์–ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„.

 


 

* Managed memory

Mono ์™€  IL2CPP ์˜ scripting virtual machines(VMs)์€ Managed memory ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

1) The managed heap: VMs ๊ฐ€ Garbage Collector ๋กœ ์ž๋™์œผ๋กœ ์ปจํŠธ๋กคํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ถ€๋ถ„.

๊ทธ๋ž˜์„œ managed heap ์— ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ GC Allocation ์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. GC Allocation ์€ Profiler ๊ฐ€ ๊ธฐ๋กํ•œ๋‹ค.

A ๋Š” ์ด์šฉ๊ฐ€๋Šฅ ์˜์—ญ
๋นˆ๊ณต๊ฐ„์€ ํ•ด์ œ๋œ ๋ถ€๋ถ„, A ๋Š” ์ƒˆ๋กœ ์ถ”๊ฐ€๋  ๋ฐ์ดํ„ฐ

 

ํšŒ์ƒ‰ ์ ์„ ๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™”๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, GC ๋Š” 1) ๋นˆ๊ณต๊ฐ„์— ๋จผ์ € ๋„ฃ๊ธฐ๋ฅผ ์‹œ๋„ํ•˜๊ณ , ์•ˆ๋  ๊ฒฝ์šฐ 2) ํž™์„ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.

* ์ด ๋•Œ, ํž™์€ ์ด์ „ ๋ฉ”๋ชจ๋ฆฌ์˜ 2๋ฐฐ ๋งŒํผ ํ™•์žฅ ๋ฉ๋‹ˆ๋‹ค. <- ์ด๊ฒŒ ๋ฌธ์ œ


ex) reference ํƒ€์ž…, boxing ๋œ ๊ฐ’ํ˜•์‹ object.

 

Built-in reference types - C# reference - C#

Learn about reference types that have C# keywords you can use to declare them.

learn.microsoft.com

 

Boxing and Unboxing - C# Programming Guide - C#

Learn about boxing and unboxing in C# programming. See code examples and view additional available resources.

learn.microsoft.com

 

2) The scripting stack: ์ฝ”๋“œ ๋ฒ”์œ„ { } ์•ˆ์—์„œ ํ• ๋‹น๋˜๊ณ  ํ•ด์ œ๋˜๋Š” ๋ถ€๋ถ„.

 

3) Native VM memory:  Unity Scripting Layer ์™€ ๊ด€๋ จ๋œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํฌํ•จ๋œ๋‹ค. Generics ์‚ฌ์šฉ๊ณผ ๊ด€๋ จ๋œ ๋ฉ”๋ชจ๋ฆฌ, reflection์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”ํƒ€ ๋ฐ์ดํ„ฐ, VMs ์„ ์‹คํ–‰ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฑด ์•Œ๊ณ  ์žˆ์ž.

 

- Managed memory์˜ ์žฅ์ : ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ํ•ด์คŒ.

- Managed memory์˜ ๋‹จ์ : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ/ํ• ๋‹น ๋ฐฉ์‹์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์–ด์„œ ๋ถˆ์•ˆ์ •ํ•œ ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์ธก ๊ฐ€๋Šฅํ•ด์•ผ๋งŒ ํ•˜๋Š” ๋ถ€๋ถ„์€ C# unmanaged memory ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

 

* C# unmanaged memory

job system, burst ๋“ฑ ๋ฉ”๋ชจ๋ฆฌ ์˜ˆ์ธก์ด ๊ฐ€๋Šฅํ•ด์•ผํ•  ๊ฒฝ์šฐ C# Collection package ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์™€ Allocator๋ฅผ ๋กœ C# unmanaged memory ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

NativeArray<int> nums = new NativeArray<int>(10, Allocator.TempJob);

// Create and schedule a job that uses the array.
ExampleJob job = new ExampleJob { Nums = nums };
JobHandle handle = job.Schedule();

// Create and schedule a job that will dispose the array after the ExampleJob has run.
// Returns the handle of the new job.
handle = nums.Dispose(handle);
 

Collections package | Collections | 2.4.0

Collections package The Collections package provides unmanaged data structures that you can use in jobs and Burst-compiled code. Additional resources

docs.unity3d.com

 

 

* Native memory

Unity ์—”์ง„ ๋‚ด๋ถ€์˜ C/C++ ์ฝ”์–ด์— ์žˆ๋Š” Native Memory. Unity ์ž์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ด๋‹ค. ์ง์ ‘ ์ ‘๊ทผ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‚˜ Profiler Marker ๋กœ ์ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์–ด๋–ค ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Unity - Manual: Common Profiler markers

Profiling your application Common Profiler markers Unity’s code is instrumented with a large number of ProfilerA window that helps you to optimize your game. It shows how much time is spent in the various areas of your game. For example, it can report th

docs.unity3d.com

 


The managed heap ์—์„œ ๋‚˜์™”๋˜ Garbage Collector ๊ฐœ๋…์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž.

 

*Garbage Collector: Unity ๊ฐ€ ๋”์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํšŒ์ˆ˜ ํ•จ.

Heap ์— ํ• ๋‹น์„ ์‹œ๋„ํ–ˆ๋Š”๋ฐ Heap์— ํ• ๋‹น์„ ์ˆ˜์š”ํ•  ์—ฌ์œ ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ Garbage Collector ๋ฅผ ์‹คํ–‰ ํ•จ.

Garbage Collector ๊ฐ€ ๋” ์ด์ƒ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ™•๋ณดํ•จ. 

 

- Garbage Collector ์†์„ฑ 2๊ฐ€์ง€

1) Incremental garbage collector: Garbage Collector ํ”„๋กœ์„ธ์Šค๋ฅผ ํ•œ๋ฒˆ์— ์‹คํ–‰ํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์— ๊ฑธ์ณ ์‹คํ–‰ํ•œ๋‹ค.

2) Incremental garbage collector disabled: Incremental GC ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด GC๊ฐ€ Heap ์˜ ๊ฐ์ฒด๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Application ์‹คํ–‰์„ ์ค‘์ง€ํ•ด๋ฒ„๋ฆฐ๋‹ค.

=> GC ๋ฅผ ์ชผ๊ฐœ์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์€ ๊ณณ๊ณผ GC ๋ฅผ ํ•œ๋ฒˆ์— ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์€ ๋ถ€๋ถ„์ด ์žˆ๊ธฐ์— Incremental GC ๋ฅผ ์‹คํ–‰์‹œ์ผœ์„œ ํ”„๋ ˆ์ž„์„ ๋–จ์–ดํŠธ๋ฆด ๊ฑด์ง€ ํ”„๋ ˆ์ž„์ด ์‚ด์ง ๋ฉˆ์ถ”๋”๋ผ๋„ ํ•œ๋ฒˆ์— ์ •๋ฆฌํ•˜๋Š”๊ฒŒ ๋‚˜์„ ๊ฒƒ์ธ์ง€ ๊ณ ๋ฏผ์ด ํ•„์š”ํ•˜๋‹ค.

3) Disable automatic garbage collector: ์ž๋™ GC ์‚ฌ์šฉ ์•ˆํ•จ. ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋กœ GC ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์‹œ๊ธฐ๋ฅผ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

// GC ํ™œ์„ฑํ™”
GarbageCollector.GCMode = GarbageCollector.Mode.Enabled;
// GC ๋น„ํ™œ์„ฑํ™”
GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;

// ์ ์ง„์  GC ์ฃผ๊ธฐ ์„ค์ •
GarbageCollector.CollectIncremental(ulong nanoseconds);

 

* GC ์˜ Allocation ์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

: Unity Profiler ์˜ CPU Usage module, Unity Profiler ์˜ Memory Module, The Memory Profiler package: 


* GC ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

1) Managed Heap ์‚ฌ์šฉ๋Ÿ‰์„ ์ค„์ด์ž.

2) ์žฌ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ Object Pool ์„ ์‚ฌ์šฉํ•˜์ž

3) ๋ฌธ์ž์—ด์„ ์—ฐ๊ฒฐํ•  ๋•Œ System.Text.StringBuilder ๋ฅผ ์‚ฌ์šฉํ•˜์ž.

: C# ์˜ ๋ฌธ์ž์—ด์€ ๋ถˆ๋ณ€์ฐธ์กฐ ์œ ํ˜•์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ์ž์—ด ๋ณ€์ˆ˜๊ฐ€ ์ผ๋‹จ ์ƒ์„ฑ๋˜๋ฉด ์ˆ˜์ •ํ•  ๋•Œ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๋ฌธ์ž์—ด์ด ์ƒ์„ฑ๋˜์–ด Heap ์— ์ €์žฅ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ์ž์—ด์„ ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค๋ฉด System.Text.StringBuilder ์‚ฌ์šฉํ•˜์ž.

using UnityEngine;

public class ExampleScript : MonoBehaviour {
    string ConcatExample(string[] stringArray) {
        string result = "";
        for (int i = 0; i < stringArray.Length; i++) {
            result += stringArray[i];
        }
        return result;
    }

}

"A", "AB", "ABC", "ABCD", "ABCDE" ๊ฐ€ heap ์— ์ €์žฅ๋œ๋‹ค. "ABCDE" ๋งŒ ์žˆ์œผ๋ฉด ๋˜๋Š”๋ฐ ๋‚˜๋จธ์ง€ ๊ฒƒ๋“ค์ด ์ค‘๋ณต ํ• ๋‹น ๋˜๋Š” ๊ฒƒ.

 

// Good C# script example: StringBuilder avoids creating temporary strings,
// and only allocates heap memory for the final result string.
using UnityEngine;
using System.Text;

public class ExampleScript : MonoBehaviour {
    private StringBuilder _sb = new StringBuilder(16);

    string ConcatExample(string[] stringArray) {
        _sb.Clear();
        for (int i = 0; i < stringArray.Length; i++) {
            _sb.Append(stringArray[i]);
        }
        return _sb.ToString();
    }
}

 

4) ๋ฐฐ์—ด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ๋ฐฐ์—ด์ด reference type ์ด๋ผ๋Š” ๊ฒƒ์„ ์ด์šฉํ•˜์ž.

using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    float[] RandomList(int numElements) {
        var result = new float[numElements];
        for (int i = 0; i < numElements; i++) {
            result[i] = Random.value;
        }
        return result;
    }
}

RandomList ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค ๋ฐฐ์—ด์ด ์ƒ์„ฑ๋˜์–ด heap ์— ํ• ๋‹น๋˜๊ณ  result ๋ฅผ ๋ฐ˜ํ™˜ํ•œ ํ›„์—๋„ result ๊ฐ’์ด heap ์— ๋‚จ์•„ ์žˆ๋Š”๋‹ค. 

 

using UnityEngine;
using System.Collections;

public class ExampleScript : MonoBehaviour {
    void RandomList(float[] arrayToFill) {
        for (int i = 0; i < arrayToFill.Length; i++) {
            arrayToFill[i] = Random.value;
        }
    }
}

์œ„์™€ ๊ฐ™์ด ์ธ์ž๋กœ ๋ณด๋‚ด๋ฉด reference type ์ด๋ฏ€๋กœ ๋ฐฐ์—ด์„ ์žฌ์‚ฌ์šฉํ•˜์—ฌ heap ์— ์ƒˆ๋กญ๊ฒŒ ํ• ๋‹น๋˜์ง€ ์•Š๋Š”๋‹ค.

 

5) Collection ๊ณผ Array ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์ž.

void Update() {
    List<float> nearestNeighbors = new List<float>();

    findDistancesToNearestNeighbors(nearestNeighbors);
    nearestNeighbors.Sort();

    // … use the sorted list somehow …
}

์œ„ ์ฝ”๋“œ๋Š” Update ๋ฌธ์ด ํ˜ธ์ถœ๋  ๋•Œ ๋งˆ๋‹ค List ๋ฅผ ๊ณ„์† ์ƒ์„ฑํ•˜์—ฌ Heap ์— ํ• ๋‹นํ•œ๋‹ค.

 

List<float> m_NearestNeighbors = new List<float>();

void Update() {
    m_NearestNeighbors.Clear();
    findDistancesToNearestNeighbors(NearestNeighbors);
    m_NearestNeighbors.Sort();

    // … use the sorted list somehow …
}

ํ•œ๋ฒˆ ์ƒ์„ฑํ•œ List ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด Heap ์— ์ƒˆ๋กœ ํ• ๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

6) Boxing ์„ ํ”ผํ•˜์ž.

: Boxing ์€ ์ž„์‹œ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์˜ ์ผ๋ฐ˜์ ์ธ ์›์ธ ์ค‘์— ํ•˜๋‚˜๋‹ค. Value ์œ ํ˜•์˜ ๋ณ€์ˆ˜๊ฐ€ Reference ์œ ํ˜•์œผ๋กœ ๋ณ€ํ™˜๋  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

int x = 1;
object y = new object();
y.Equals(x);

 

7) Array-valued Unity APIs๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ single array allocation ์„ ์ด์šฉํ•˜์ž.

void Update() {
    for(int i = 0; i < mesh.vertices.Length; i++) {
        float x, y, z;

        x = mesh.vertices[i].x;
        y = mesh.vertices[i].y;
        z = mesh.vertices[i].z;

        // ...

        DoSomething(x, y, z);   
    }
}

Loop ์•ˆ์— mesh.vertices.Length๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด Loop ๊ฐ€ 1ํšŒ ๋™์ž‘ํ•  ๋•Œ๋งˆ๋‹ค 4๊ฐœ์˜ ์ •์  ๋ฐฐ์—ด ๋ณต์‚ฌ๋ณธ์„ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ํ• ๋‹น์€ .vertices ์†์„ฑ์— ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ์ด๋ฃจ์–ด์ง„๋‹ค.

 

void Update() {
    var vertices = mesh.vertices;

    for(int i = 0; i < vertices.Length; i++) {

        float x, y, z;

        x = vertices[i].x;
        y = vertices[i].y;
        z = vertices[i].z;

        // ...

        DoSomething(x, y, z);   
    }
}

Loop ๊ตฌ๋ฌธ ์ „์— vertices ๋ฅผ ์ €์žฅํ•˜์—ฌ single array ํ• ๋‹น์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

List<Vector3> m_vertices = new List<Vector3>();

void Update() {
    mesh.GetVertices(m_vertices);

    for(int i = 0; i < m_vertices.Length; i++) {

        float x, y, z;

        x = m_vertices[i].x;
        y = m_vertices[i].y;
        z = m_vertices[i].z;

        // ...

        DoSomething(x, y, z);   
    }
}

๊ฐ€์žฅ ๋ฒ ์ŠคํŠธ๋Š” ์œ„์˜ ์ฝ”๋“œ ์ด๋‹ค. Update ๊ตฌ๋ฌธ ๋ฐ–์—์„œ vertice ๋“ค์„ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฒƒ.

 

๊ทธ ์™ธ ํ• ๋‹น๋˜๋Š” API์™€ ํ• ๋‹น๋˜์ง€ ์•Š๋Š” API ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด Non-allocating API ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด๋‹ค.

728x90