Version: 2023.2
언어: 한국어
Unity에서 메모리
가비지 컬렉터 개요

관리되는 메모리

Unity의 관리되는 메모리 시스템Mono 또는 IL2CPP 가상 머신(VM)기반의 C# 스크립팅 환경입니다. 관리되는 메모리 시스템의 이점은 메모리 해제를 관리하므로 코드를 통해 메모리 해제를 수동으로 요청할 필요가 없다는 것입니다.

Unity의 관리되는 메모리 시스템은 가비지 컬렉터관리되는 힙을 사용하여 스크립트에 해당 할당에 대한 레퍼런스가 더 이상 없으면 메모리 할당을 자동으로 해제합니다. 이는 메모리 누수를 방지하는 데 도움이 됩니다. 메모리는 할당되었으나 레퍼런스가 손실되면 메모리 누수가 발생하고 메모리를 해제하려면 레퍼런스가 필요하기 때문에 메모리가 해제되지 않습니다.

이 메모리 관리 시스템은 또한 메모리 액세스를 보호합니다. 즉, 해제되었거나 코드가 액세스하는 데 유효하지 않은 메모리에 액세스할 수 없게 합니다. 그러나 메모리 관리 프로세스는 관리되는 메모리를 할당하는 데 시간이 많이 걸리기 때문에 런타임 성능에 영향을 미칩니다. 가비지 컬렉션은 CPU가 완료될 때까지 다른 작업을 수행하지 못하게 할 수도 있습니다.

값 타입과 레퍼런스 타입

메서드가 호출되면 스크립팅 백엔드는 해당 파라미터의 값을 호출 스택이라는 데이터 구조의 특정 호출을 위해 예약된 메모리 영역에 복사합니다. 스크립팅 백엔드는 몇 바이트를 차지하는 데이터 유형을 빠르게 복사할 수 있습니다. 그러나 오브젝트, 문자열, 배열은 훨씬 더 용량이 큰 것이 일반적이며 스크립팅 백엔드에서 이러한 유형의 데이터를 정기적으로 복사하는 것은 비효율적입니다.

관리되는 코드의 모든 null이 아닌 레퍼런스 형식의 오브젝트와 모든 박싱된 값 형식의 오브젝트가 관리되는 힙에 할당되어야 합니다.

코드를 효과적으로 관리하려면 값 타입과 레퍼런스 타입에 익숙해지는 것이 중요합니다. 자세한 내용은 값 타입레퍼런스 타입에 대한 Microsoft 문서를 참조하십시오.

자동 메모리 관리

오브젝트가 생성되면 Unity 프로젝트에서 선택한 스크립팅 런타임(Mono 또는 IL2CPP)이 자동으로 관리하는 메모리 섹션인 이라는 중심 풀에서 오브젝트를 저장하는 데 필요한 메모리를 할당합니다. 오브젝트가 더 이상 사용되지 않으면 한 번 점유했던 메모리를 회수하여 다른 용도로 사용할 수 있습니다.

Unity의 스크립팅 백엔드가비지 컬렉터를 사용하여 애플리케이션의 메모리를 자동으로 관리하므로 명시적인 메서드 호출로 이러한 메모리 블록을 할당/해제할 필요가 없습니다. 자동 메모리 관리는 명시적 할당/해제보다 코딩 작업이 덜 필요하며 메모리 누수의 가능성을 줄여줍니다.

관리되는 힙 개요

관리되는 힙은 Unity 프로젝트에서 선택한 스크립팅 런타임(Mono 또는 IL2CPP)이 자동으로 관리하는 메모리 섹션입니다.

메모리 용량. 다이어그램에서 A로 표시된 부분은 사용 가능한 메모리입니다.
메모리 용량. 다이어그램에서 A로 표시된 부분은 사용 가능한 메모리입니다.

위의 다이어그램에서 파란 상자는 관리되는 힙에 할당하는 메모리 양을 나타냅니다. 그 안의 흰 상자는 관리되는 힙의 메모리 공간에 저장하는 데이터 값을 나타냅니다. 추가 데이터 값이 필요한 경우에는 관리되는 힙에서 여유 공간(A로 표시)을 할당합니다.

메모리 단편화와 힙 확장

회색 점선으로 표시된 일부 오브젝트가 해제된 메모리 용량입니다.
회색 점선으로 표시된 일부 오브젝트가 해제된 메모리 용량입니다.

위의 다이어그램은 메모리 단편화의 예를 보여줍니다. Unity에서 오브젝트를 해제하면 오브젝트가 차지했던 메모리가 확보됩니다. 하지만, 그 빈 공간은 하나의 큰 “자유 메모리” 풀의 일부가 되지 않습니다.

해제된 오브젝트의 양쪽에 있는 오브젝트가 여전히 사용 중일 수 있습니다. 이로 인해 반환된 공간은 사용 중인 메모리 세그먼트 사이의 “간극”이 됩니다. 반환된 공간은 해제된 오브젝트의 용량과 같거나 적은 데이터를 저장하는 데에만 사용할 수 있습니다.

이 현상을 메모리 단편화라고 합니다. 이 문제는 힙에서 사용할 수 있는 메모리 양은 많지만 오브젝트 간의 “간극”으로 이루어진 경우에 발생합니다. 즉, 대규모 메모리 할당을 위한 전체 공간이 충분하더라도 관리되는 힙은 할당할 만큼 충분히 큰 연속된 메모리 블록을 찾을 수 없습니다.

A로 표시된 오브젝트는 힙에 추가해야 하는 새 오브젝트입니다. B로 표시된 항목은 해제된 오브젝트가 차지한 메모리 공간과 예약되지 않은 여유 메모리입니다. 전체 여유 공간이 충분하더라도 연속된 공간이 충분하지 않기 때문에 A로 표시된 새 오브젝트에 대한 메모리가 힙에 맞지 않으므로 가비지 컬렉터가 실행되어야 합니다.
A로 표시된 오브젝트는 힙에 추가해야 하는 새 오브젝트입니다. B로 표시된 항목은 해제된 오브젝트가 차지한 메모리 공간과 예약되지 않은 여유 메모리입니다. 전체 여유 공간이 충분하더라도 연속된 공간이 충분하지 않기 때문에 A로 표시된 새 오브젝트에 대한 메모리가 힙에 맞지 않으므로 가비지 컬렉터가 실행되어야 합니다.

만일 용량이 큰 오브젝트가 할당되었으나 이를 수용할 만한 충분한 크기의 연속된 공간이 없는 경우 위에서 보이는 것과 같이, Unity 메모리 관리자는 두 개의 작업을 실행합니다.

  • 우선, 가비지 컬렉터가 아직 실행되지 않은 경우 이를 실행시킵니다. 이는 할당 요청을 수용할 수 있는 충분한 공간을 만들 수 있도록 시도합니다.
  • 가비지 컬렉터가 실행된 이후에도 요청된 메모리 공간을 수용할 수 있는 연속된 공간이 없는 경우에는 힙을 확장시킵니다. 힙이 확장하는 구체적인 양은 플랫폼에 따라 다르지만, 대부분의 플랫폼에서는 힙이 확장될 때 이전 확장의 두 배만큼 확장됩니다.

관리되는 힙 확장 시 고려 사항

예기치 않은 힙 확장은 문제가 될 수 있습니다. Unity의 가비지 컬렉션 전략은 메모리를 더 자주 단편화하는 경향이 있으므로 다음 사항에 유의해야 합니다.

  • Unity는 정기적으로 확장될 때 관리되는 힙에 할당된 메모리를 해제하지 않습니다. 대신 확장된 힙의 많은 섹션이 비어 있어도 그대로 유지합니다. 이는 더 큰 할당이 발생하는 경우 힙을 다시 확장해야 할 필요가 없도록 하기 위한 것입니다.
  • 대부분의 플랫폼에서 Unity는 결국 관리되는 힙의 빈 부분을 운영체제에서 다시 사용하도록 메모리 해제합니다. 이러한 일이 발생하는 간격은 보장되지 않으며 신뢰할 수 없습니다.
  • 가비지 컬렉터는 네이티브 메모리 오브젝트나 기타 네이티브 할당을 지우지 않습니다. Resources.UnloadUnusedAssets는 더 이상 가리키는 참조가 없는 모든 네이티브 오브젝트에 대해 이를 수행합니다. 또한 GC.Collect를 트리거하여 이러한 참조가 최신 상태를 유지하도록 합니다. 다음에 유의하십시오.
    • UnloadUnusedAssets는 자동으로 트리거되지 않으며, 씬이 변경될 때만 수동으로 트리거됩니다. 예를 들어 RAM이 낮은 플랫폼에서 전체 화면 RenderTextures에 대해 중요할 수 있는 메모리를 더 일찍 해제하려면 오브젝트에 대해 Destroy를 호출하여 보유하고 있는 메모리를 최적의 방식으로 사용해야 합니다.
    • 관리되는 메모리가 누수될 위험이 있습니다. 정리된 오브젝트에 대한 참조를 유지하면 관리되는 오브젝트가 참조하는 네이티브 오브젝트가 누수될 위험이 있습니다. 정적 필드와 이벤트는 이러한 메모리 누수의 일반적인 원인입니다. 메모리 프로파일러로 이러한 문제를 분석하는 자세한 방법은 메모리 프로파일러 패키지 기술 자료에서 관리되는 셸 오브젝트를 참조하십시오.
    • UnloadUnusedAssets 또는 GC.Collect를 호출하면 CPU 소모량이 높은 프로세스가 트리거되므로 게임플레이 중에는 이를 피하고 싶을 수 있습니다.
Unity에서 메모리
가비지 컬렉터 개요