Unity의 관리되는 메모리 시스템은 Mono 또는 IL2CPP 가상 머신(VM)기반의 C# 스크립팅 환경입니다. 관리되는 메모리 시스템의 이점은 메모리 해제를 관리하므로 코드를 통해 메모리 해제를 수동으로 요청할 필요가 없다는 것입니다.
Unity의 관리되는 메모리 시스템은 가비지 컬렉터와 관리되는 힙을 사용하여 스크립트에 해당 할당에 대한 레퍼런스가 더 이상 없으면 메모리 할당을 자동으로 해제합니다. 이는 메모리 누수를 방지하는 데 도움이 됩니다. 메모리는 할당되었으나 레퍼런스가 손실되면 메모리 누수가 발생하고 메모리를 해제하려면 레퍼런스가 필요하기 때문에 메모리가 해제되지 않습니다.
이 메모리 관리 시스템은 또한 메모리 액세스를 보호합니다. 즉, 해제되었거나 코드가 액세스하는 데 유효하지 않은 메모리에 액세스할 수 없게 합니다. 그러나 메모리 관리 프로세스는 관리되는 메모리를 할당하는 데 시간이 많이 걸리기 때문에 런타임 성능에 영향을 미칩니다. 가비지 컬렉션은 CPU가 완료될 때까지 다른 작업을 수행하지 못하게 할 수도 있습니다.
메서드가 호출되면 스크립팅 백엔드는 해당 파라미터의 값을 호출 스택이라는 데이터 구조의 특정 호출을 위해 예약된 메모리 영역에 복사합니다. 스크립팅 백엔드는 몇 바이트를 차지하는 데이터 유형을 빠르게 복사할 수 있습니다. 그러나 오브젝트, 문자열, 배열은 훨씬 더 용량이 큰 것이 일반적이며 스크립팅 백엔드에서 이러한 유형의 데이터를 정기적으로 복사하는 것은 비효율적입니다.
관리되는 코드의 모든 null이 아닌 레퍼런스 형식의 오브젝트와 모든 박싱된 값 형식의 오브젝트가 관리되는 힙에 할당되어야 합니다.
코드를 효과적으로 관리하려면 값 타입과 레퍼런스 타입에 익숙해지는 것이 중요합니다. 자세한 내용은 값 타입과 레퍼런스 타입에 대한 Microsoft 문서를 참조하십시오.
오브젝트가 생성되면 Unity 프로젝트에서 선택한 스크립팅 런타임(Mono 또는 IL2CPP)이 자동으로 관리하는 메모리 섹션인 힙이라는 중심 풀에서 오브젝트를 저장하는 데 필요한 메모리를 할당합니다. 오브젝트가 더 이상 사용되지 않으면 한 번 점유했던 메모리를 회수하여 다른 용도로 사용할 수 있습니다.
Unity의 스크립팅 백엔드는 가비지 컬렉터를 사용하여 애플리케이션의 메모리를 자동으로 관리하므로 명시적인 메서드 호출로 이러한 메모리 블록을 할당/해제할 필요가 없습니다. 자동 메모리 관리는 명시적 할당/해제보다 코딩 작업이 덜 필요하며 메모리 누수의 가능성을 줄여줍니다.
관리되는 힙은 Unity 프로젝트에서 선택한 스크립팅 런타임(Mono 또는 IL2CPP)이 자동으로 관리하는 메모리 섹션입니다.
위의 다이어그램에서 파란 상자는 관리되는 힙에 할당하는 메모리 양을 나타냅니다. 그 안의 흰 상자는 관리되는 힙의 메모리 공간에 저장하는 데이터 값을 나타냅니다. 추가 데이터 값이 필요한 경우에는 관리되는 힙에서 여유 공간(A로 표시)을 할당합니다.
위의 다이어그램은 메모리 단편화의 예를 보여줍니다. Unity에서 오브젝트를 해제하면 오브젝트가 차지했던 메모리가 확보됩니다. 하지만, 그 빈 공간은 하나의 큰 “자유 메모리” 풀의 일부가 되지 않습니다.
해제된 오브젝트의 양쪽에 있는 오브젝트가 여전히 사용 중일 수 있습니다. 이로 인해 반환된 공간은 사용 중인 메모리 세그먼트 사이의 “간극”이 됩니다. 반환된 공간은 해제된 오브젝트의 용량과 같거나 적은 데이터를 저장하는 데에만 사용할 수 있습니다.
이 현상을 메모리 단편화라고 합니다. 이 문제는 힙에서 사용할 수 있는 메모리 양은 많지만 오브젝트 간의 “간극”으로 이루어진 경우에 발생합니다. 즉, 대규모 메모리 할당을 위한 전체 공간이 충분하더라도 관리되는 힙은 할당할 만큼 충분히 큰 연속된 메모리 블록을 찾을 수 없습니다.
만일 용량이 큰 오브젝트가 할당되었으나 이를 수용할 만한 충분한 크기의 연속된 공간이 없는 경우 위에서 보이는 것과 같이, Unity 메모리 관리자는 두 개의 작업을 실행합니다.
예기치 않은 힙 확장은 문제가 될 수 있습니다. Unity의 가비지 컬렉션 전략은 메모리를 더 자주 단편화하는 경향이 있으므로 다음 사항에 유의해야 합니다.
GC.Collect
를 트리거하여 이러한 참조가 최신 상태를 유지하도록 합니다. 다음에 유의하십시오.
UnloadUnusedAssets
는 자동으로 트리거되지 않으며, 씬이 변경될 때만 수동으로 트리거됩니다. 예를 들어 RAM이 낮은 플랫폼에서 전체 화면 RenderTextures에 대해 중요할 수 있는 메모리를 더 일찍 해제하려면 오브젝트에 대해 Destroy를 호출하여 보유하고 있는 메모리를 최적의 방식으로 사용해야 합니다.UnloadUnusedAssets
또는 GC.Collect
를 호출하면 CPU 소모량이 높은 프로세스가 트리거되므로 게임플레이 중에는 이를 피하고 싶을 수 있습니다.