[Unity] 오브젝트 생성/삭제시 Editor에서 메모리 해제가 잘 안된다면

Unity editor에서 프로젝트를 실행하고, Profiler를 이용하여 메모리 상태를 확인하는 경우 게임오브젝트를 생성후 삭제했음에도 불구하고, 여전히 메모리에 레퍼런스가 잡혀 있는 경우가 있다.  디바이스에서는 발생하지 않는 경우라서 editor 내부에서 캐시를 하는 경우로 보이지만, 매번 디바이스에서 프로파일링하여 확인하는 것도 여간 번거로운 일이 아니다. 

시간을 줄이고 생산성을 높이자면 editor에서도 어느 정도 정확한 메모리 정보가 필요하다.  예를 들어 하나의 게임오브젝트를 생성하고 파괴했을 때를 반복하는 경우에 캐시되는 정보들로 인해 처음 시도할 때와 그 이후에 시도할 때의 메모리 차이는 같지 않을 것이다.  메모리 해제가 안되는 이유를 확인하기 위해 간단히 테스트를 해보았다. 

Scene에 게임오브젝트를 하나 만들고, 이름을 IamGameObject라고 명명하였다. 여기에 Animation Component를 추가하고, 더미 AnimationClip을 하나 생성하여 링크시켰다.  

Hierarchy view
Attach Dummy Animation

이제 프로젝트를 실행하여, Profiler상에 메모리 상태를 확인해보자. (메뉴 Window > Profiler를 선택) Memory 섹션을 누르고, 아래 정보창에서 Detailed를 선택후 Take Sample:Editor를 선택하면 현재 메모리 스냅샷을 찍을 수 있다.

Profiler: Take Memory Snapshot

여러 정보들이 있지만, Assets 아래에 있는 Animation 정보를 한번 트래킹해보자.

Profiler: reference info

Animation을 보면 GameObject가 0.7KB의 메모리를 차지하고 있고, 오른쪽에는 레퍼런스 정보를 볼 수 있다.  두개의 레퍼런스로 인해 0.7KB 만큼 차지한다는 것이다.

자, 그럼 이제 IamGameObject를 삭제하여 실제로 메모리가 해제되는지 살펴보자. DeleteObject.cs라는 Script를 하나 생성하고, 프로젝트 실행후 3초후에 위에 IamGameObject를 삭제해보았다.  (이 Script는 MainCamera에 Attach하였다!)

public class DeleteObject : MonoBehaviour {
    // Use this for initialization
    void Start() {
        StartCoroutine(coDelete());
    }
    IEnumerator coDelete()
    {
        yield return new WaitForSeconds(3);
        GameObject obj = GameObject.Find("IamGameObject");
        if (obj)
        {
            Debug.Log("Destory GameObject");
            Destroy(obj);
        }
    }
}

다시 프로젝트를 실행하여, 해당 게임오브젝트가 삭제되는 것을 확인하고, Profiler를 체크 해보자.

Profiler: reference info

Reference By 섹션에 IamGameObject(Animation)이 삭제되어 더 이상 표시가 되지 않지만, GameObject(GameObject)는 남아 있었다.  저것 때문에 여전히 메모리에 0.7KB가 잡혀 있다.  아직 삭제가 다 안된 것인지 확인하기 위해 다시 Take Sample:Editor를 눌러 확인 해보았지만 같은 결과였다.  Hierarchy뷰에서도 노출은 되지 않았다.

Hierarchy view

구글링을 하는 와중에, 유니티 메뉴얼에서 asset unload 관련하여 함수가 있다는 것을 발견하였다. (Manual)

EditorUtility.UnloadUnusedAssetsImmediate()

사용하지 않는 asset을 unload하는 editor 함수여서, 위의 코드에 추가하여 다시 테스트 해보았다.

public class DeleteObject : MonoBehaviour {
    // Use this for initialization
    void Start() {
        StartCoroutine(coDelete());
    }
    IEnumerator coDelete()
    {
        yield return new WaitForSeconds(3);
        GameObject obj = GameObject.Find("IamGameObject");
        if (obj)
        {
            Debug.Log("Destory GameObject");
            Destroy(obj);
        }
<b>
#if UNITY_EDITOR
        yield return null;
        EditorUtility.UnloadUnusedAssetsImmediate(true);
#endif
</b>
    }
}

이렇게 테스트를 해보니, Animation에 있던 0.7KB가 해제된 것을 확인할 수 있었다. (Destory는 실제로 오브젝트가 파괴되는 시점에 딜레이가 있기 때문에, yield return null을 추가하여 한 프레임 후에 unload를 시도하였다.)

Profiler: Animation 항목이 사라짐

참고로 테스트 환경은 Unity 2017.4.28f1 / Windows 이다.


Leave a Reply

Your email address will not be published. Required fields are marked *