"눈이 나쁘면 안경을 쓴댔으니 모자란 너에겐 모자를 씌워주마" – 김케장 / 동전주머니엔 동전이 들었지

20130531
Destroy와 DestroyImmediate

유니티 2버전부터 지금까지 쓰면서 설명 대충 보고 쓰다가 잘못 알고 있는 걸 이번에 제대로 알게 돼서 적어둡니다. 먼저 함수 설명을 봅시다.


public static void Destroy( Object obj, float t = 0.0f )

GameObject, Component나 Asset을 파괴합니다.

객체 obj가 지금 파괴되거나 t에 적힌 시간이 지난 후 파괴됩니다. obj가 Component이면 GameObject에서 해당 Component를 제거한 후 파괴합니다. obj가 GameObject인 경우 GameObject가 파괴되고 연결된 모든 Component와 transform 아래로 있는 자식들이 파괴됩니다. 실제 객체 파괴는 항상 현재 Update 루프가 끝나기 전까지 지연되며 렌더링이 되기 전에 파괴됩니다.

Destroy는 UnityEngine.Object 부모 클래스를 상속 받습니다. Javascript 사용자는 .Net의 System.Object 클래스가 참조되는 문제를 피하기 위해 함수 호출시 Object.Destroy보다는 UnityEngine.Object.Destroy를 사용해야 할 것입니다.


public static void DestroyImmediate( Object obj, bool allowDestroyingAssets = false )

객체 obj를 즉시 파괴합니다. Destroy를 사용할 것을 강력히 권합니다.

편집 모드에서는 지연 파괴가 아예 실행되지 않으므로 이 함수는 편집 코드를 작성할 때만 사용해야 합니다. 게임 코드 작성 시에는 대신 Destroy를 사용하길 바랍니다. Destroy는 항상 지연(되지만 같은 프레임 내에서 실행)됩니다. 이 함수는 영구적으로 Asset을 파괴하므로 사용 시 주의를 필요로 합니다! 또한, 절대로 배열을 돌면서 돌고 있는 배열요소를 파괴하면 안 된다는 것을 알아야 합니다. 이는 심각한 문제를 일으킬 수 있습니다. (유니티에서만이 아니라 일반 프로그래밍에서도 적용되는 이야기. 배열이 있다고 하고 배열을 도는 도중 배열 요소를 지워버리면 반복문은 남은 횟수를 마저 돌겠지만, 배열은 요소가 줄어 아예 다른 주소를 참조하거나 잘못된 주소를 참조하게 되어 예외가 발생합니다.)


원래 있던 건지 언제 생겼는지 DestroyObject라고 하나 더 있는데 레퍼런스에도 안 나오고 생긴 것 봐서는 Destroy랑 별 차이 없어 보이네요.

위에 나온 대로 DestroyImmediate는 주로 편집 모드(플레이 버튼을 눌러서 게임이 실행 중인 게 아니라 그냥 유니티를 켠 상태)에서만 써야 합니다. 하지만 게임 모드(런타임, 게임이 실행 중)에서 써도 크게 문제 되지는 않는 것으로 보입니다. (위에 설명에서도 안 쓰는 걸 권하고 있고 상황을 전부 테스트해본 게 아니라서 확답은 아닙니다.)

둘의 차이는 첫 번째로 파괴의 시점입니다. Destroy는 당장 파괴가 되지 않습니다. 다시 말해서 Destroy가 불린 Update 프레임 내에서 파괴한 객체를 다시 불러도 해당 객체는 null이 아니라는 이야기. 해당 객체는 Update 프레임이 끝나야 파괴됩니다. 반대로 DestroyImmediate는 불린 즉시 객체가 파괴되며 해당 객체는 null이기 때문에 다시 부르면 Null참조예외가 일어납니다.

두 번째 차이는 Asset 파괴 가능 유무입니다. 일단 먼저 말하지만 Asset(텍스처, 오디오파일 등등)은 게임 모드일 때 파괴(메모리 해제가 아니고 진짜 파괴.) 하는 게 아닙니다! Destroy나 DestroyImmediate 둘 다 런타임 때 Asset에 사용하면 다음과 같은 에러가 발생합니다.

데이터 유실을 피하고자 Asset 파괴는 허용하지 않습니다.
정말로 Asset 파괴를 원하는 경우 DestroyImmediate( Object, true );를 사용하세요.

근데 에러에 나온 대로 DestroyImmediate의 두 번째 파라미터를 true(기본은 false)로 주고 게임 모드 때 Asset을 파괴하면 잠시 멈칫했다가 유니티 자체가 죽습니다;; 혹여나 직접 해봤는데 유니티가 죽지 않는다고 해도 실제로 이렇게 쓸 일도 없겠지만, 그냥 쓰지 맙시다….

위에 설명에서는 편집 모드에서 파괴하면 실제로 파일이 삭제될 것 같은 뉘앙스인데 물리디스크에서 삭제되는 것은 아닙니다. 파괴 후 Project탭을 보면 파일이 보이긴 하나 클릭해서 Inspector탭을 보면 정보가 아무것도 안 나오며 사용도 안 되고 없는 파일 취급당합니다. 유니티를 다시 켜면 파일 이름만 보이고요. 다시 파일을 사용하려면 meta 파일을 사용하는 경우 meta 파일을 지우고 유니티를 띄워 다시 유니티가 meta 파일을 생성하게 해서 목록을 갱신시키거나 meta 파일을 사용하지 않는 경우 파일을 다른 곳으로 옮긴 후 유니티를 띄워서 목록을 갱신시키고 파일을 다시 원래 있던 곳으로 넣은 후 유니티를 띄워 목록을 다시 갱신시키면 됩니다.

끝으로 함수 사용 목적이 사용하지 않는 Asset을 메모리에서 내리기(해제하기) 위한 것이라면 Resources.UnloadAsset을 사용해 해당 Asset을 직접 내리거나 Resources.UnloadUnusedAssets를 사용해서 사용하지 않는 Asset 모두를 내리면 됩니다.

댓글 남기기 | 타닥타닥

댓글 남기기

* 표시된 곳은 반드시 입력해주세요