티스토리 뷰

이번에 개발하다가 사운드 클립 리소스를 필요할 때 메모리에 올리고 사용이 끝나면 모든 레퍼런스를 제거하는 로직의 스크립트를 작성했다. (유지보수를 위한 커스텀 GUI는 덤)

 

하지만 해당 리소스의 모든 레퍼런스를 제거했어도 실제로 메모리에서 해당 사운드 클립 리소스가 내려오지는 않았다.

 

아마 메모리가 부족해진다면 가장 먼저 가비지컬렉터에 의해 정리되긴 하겠지만 이렇게 레퍼런스가 없더라도 정리되지 않는 이유라면 굳이 매번 레퍼런스가 0인 데이터를 제거하는 것도 시간이 걸리는 작업이고 아마 캐싱 같은 개념으로 사용할 수 있을 것 같다.

 

리소스의 메모리 사용 과정
  1. A라는 사운드 클립을 사용하려 한다.
  2. 저장소에서 메모리로 A 사운드 클립 데이터가 올라온다.
  3. 올라온 데이터를 신나게 쓴다.
  4. 다쓰고 해당 데이터와 연관된 모든 오브젝트를 파괴한다.
  5. 레퍼런스가 없지만 메모리에 남아있다.
  6. 다음에 또 A 사운드 클립을 사용할 때, 기존 메모리에 올라와 있는 리소스를 사용한다.

 

 


비교 테스트

다음은 '00_UI_Click 0'라는 오디오 클립에 대한 레퍼런스 변화를 찍은 스냅샷 비교 사진이다.

단, 이 실험에는 다음과 같은 전제조건이 있다.

 

전제조건

  • 하나의 리소스를 사용하는 수개의 레퍼런스가 존재한다.
  • 해당 실험에 사용되는 리소스는 'Resources' 디렉토리에 존재하지 않는다.
    • 잘못된 정보 표기로 'Resources'에 있더라도 Load메서드를 통해서 메모리에 로드된다.

 

 

모든 레퍼런스가 살아있는 경우

 

가장 첫 스냅샷에서 해당 리소스는 11개의 레퍼런스가 있다.

당연하게도 동일한 리소스를 사용하기에 해당 리소스 하나만 메모리에 올라가고 해당 리소스를 사용하는 레퍼런스만 11개가 존재한다.

 

 

일부 레퍼런스를 제거한 경우

 

11개의 레퍼런스 중 2개를 제외한 모든 오브젝트를 제거했다.

모든 레퍼런스가 존재하는 경우와 동일하다.

 

모든 레퍼런스를 제거한 경우

 

이제 모든 레퍼런스를 제거했다.

그런데 유니티는 해당 리소스를 메모리에서 제거하지 않고 있다.

 

이러한 경우는 여러 조건에 의해 발생할 수 있다. 뭐 대충 예를 들면 다음과 같다.

 

 

GC(Garbage Collection)이 발생하지 않았을 수 있음

유니티의 가비지 컬렉션은 레퍼런스가 모두 제거된 오브젝트를 정리하는 과정이다. 하지만 GC는 시스템의 상태와 사용 패턴에 따라 발생할 수 있으며, 레퍼런스가 모두 제거되어도 즉시 발생하지 않을 수 있다.

 

오디오 클립이 리소스 폴더에 로드되어 있을 수 있음

리소스 폴더에 로드된 리소스는 명시적으로 해제하기 전까지 메모리에 상주한다. 따라서 리소스 폴더에 로드된 오디오 클립을 사용하고 있다면, 해당 클립은 레퍼런스가 모두 제거되어도 메모리에 남아 있을 수 있다.

 

※ 물론 이번 테스트에 전제조건이 리소스 폴더에서 가져오는 것이 아니기에 이 조건은 해당하지 않는다.

 

캐싱되어 있을 수 있음

유니티의 AudioManager나 다른 관리 시스템에서 오디오 클립을 캐싱하여 메모리에 상주시킬 수 있다. 이 경우에는 해당 시스템을 통해 캐시된 오디오 클립을 명시적으로 해제해야 한다.

 

기타 메모리 관리 이슈

유니티 메모리 관리는 복잡할 수 있으며, 메모리 해제에 영향을 줄 수 있는 다양한 요소가 있다. 런타임 중에 메모리 상태를 확인하고 적절한 해제 작업을 수행해야 한다.

 

 

실제 메모리 Unload

 

그럼 방법이 없느냐? 그것도 아니다.

 

위 사진은 유니티에서 스크립트를 통해 원하는 시점에 사용되지 않는 리소스를 메모리에서 해제한 것이다.

이 동작을 하기위한 함수 호출과정은 굉장히 간단하다.

 

Resources.UnloadUnusedAssets();

 

이 코드 한줄이면 된다.

물론 강제로 GC를 실행시킬 수 있기도 하다.

 

 


테스트 2

이번에는 유니티 오브젝트와 관련되어 테스트를 해보았다. 테스트 내용은 다음과 같다.

 

  1. 오브젝트는 놔두고 해당 리소스를 사용하던 스크립트만 제거한 경우
  2. 오브젝트까지 완벽히 파괴하는 경우

 

using System.Collections;
using System.Collections.Generic;

using UnityEngine;

[System.Serializable]
public class SoundContainer
{
    public int          IntegerFlag;
    public SFXList      EnumFlag;
    public AudioClip    Clip;
}

public class SoundUnit : MonoBehaviour
{
    [Header("Clip informations")]
    public List<SoundContainer> ClipList = new List<SoundContainer>();

    private void OnDestroy()
    {
    	// 모든 ClipList를 제거하는 로직
    }
}

 

이게 이번 테스트에 사용될 오브젝트이다. 스크립트도 간단하다.

 

 

스크립트만 제거하는 경우

스크립트만 제거하는 경우에도 OnDestroy 함수는 발동한다.

하지만 해당 스크립트를 가지고 있던 오브젝트가 해당 함수에서 사용하던 컨테이너를 따로 정리해주지 않는다면 생성된 값은 해당 오브젝트에 묶여있다.

 

 

초기 상태

위 사진은 가장 초기에 'SoundContainer' 객체를 가진 'SoundItem'스크립트가 존재하는 상태이다.

 

스크립트 제거

위 그림은 스크립트만 제거한 상황이다. 해당 오디오 클립 리소스 레퍼런스에서 'SoundItem' 스크립트가 제거된 것을 알 수 있다.

 

하지만 해당 객체가 사용되던 오브젝트가 살아있어서 실제 데이터를 가지고 있는 'SoundContainer'객체가 남아있는 것을 알 수 있다.

 

Resouces.UnloadAsset 함수 호출

위 사진은 'SoundContainer'객체가 남아있는 상태에서 Resources.UnloadAsset 함수를 발동시킨 것이다.

예상했던 것과 같이 레퍼런스가 남아있기 때문에 실제 데이터가 메모리에서 제거되지 않았다.

 

문제는 여기서 끝나지 않는다. 스크립트를 먼저 제거하고 오브젝트를 파괴하면 실제 해당 객체를 사용하던 오브젝트에 묶여있던 객체 정보는 Resources.UnloadAsset함수를 호출해도 해당 레퍼런스가 해제되지가 않는다.

 

대체 방법

그럼 위와 같은 상황을 대처할 수 없는가? (물론 스크립트만 제거하는 경우는 발생할 일이 없긴하다...)

해당 방법을 처리하기 위해서는 다음과 같이 'OnDestroy'로 정리할 때, 내부 컨테이너를 비워주면 된다.

 

그렇게 된다면 해당 리소스를 포함하는 모든 데이터가 제거되기에 레퍼런스가 0개가 되고 메모리에서 원하는 시점에 제거할 수 있게 된다.

 

using System.Collections;
using System.Collections.Generic;

using UnityEngine;

[System.Serializable]
public class SoundContainer
{
    public int          IntegerFlag;
    public SFXList      EnumFlag;
    public AudioClip    Clip;
}

public class SoundUnit : MonoBehaviour
{
    [Header("Clip informations")]
    public List<SoundContainer> ClipList = new List<SoundContainer>();

    private void OnDestroy()
    {
        ClipList.Clear();  // 파괴와 동시에 리스트 객체들을 모두 제거한다.
    }
}

 

 

오브젝트까지 제거하는 경우

 

오브젝트가 파괴되어 당연하게도 OnDestroy 함수가 발동한다.

오브젝트까지 제거한 경우, Resources.UnloadAsset함수를 통해 실제 모든 데이터를 제거할 수 있다.

 

'개발 > Unity' 카테고리의 다른 글

[Unity] 🧙‍♂️ God Object  (0) 2025.05.21
[Unity] 유니티 최적화 체크 리스트  (0) 2025.05.15
[Unity] SOLID 원칙과 게임 개발  (1) 2024.03.31
[Unity] Custom Editor  (0) 2023.09.03
[Unity] 인스펙터 레이아웃 생성 과정  (0) 2023.09.03
최근에 올라온 글
최근에 달린 댓글
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함