게임 개발 중, 동적으로 생성된 오브젝트를 파괴하고 메모리를 정리하는 작업은 매우 중요합니다. 특히 유니티(Unity)에서는 스크립트(Script)와 게임 오브젝트(GameObject)를 관리할 때, 잘못된 메모리 관리로 인해 성능 저하나 메모리 누수가 발생할 수 있습니다.
이번 포스팅에서는 List<Script>에 저장된 스크립트와 관련된 게임 오브젝트를 최적화된 방법으로 **파괴(Destroy)**하고, 리스트를 정리하는 방법에 대해 알아보겠습니다.
1. 문제 상황
예를 들어, 우리가 게임 중 동적으로 생성한 오브젝트의 스크립트를 List<Script>에 저장했다고 가정해 봅시다. 게임이 진행되면서 특정 조건에서 이 오브젝트를 "파괴(Destroy)"하고 리스트를 정리(Clear)해야 할 필요가 있습니다.
다음과 같은 작업이 필요합니다:
- 스크립트와 연결된 게임 오브젝트를 파괴 (메모리에서 해제).
- 리스트를 초기화 및 정리 (메모리 최적화).
- 파괴 중 이미 파괴된 오브젝트나 null 참조 문제 방지.
2. 최적화된 코드 구현
다음은 위 문제를 해결하기 위한 최적화된 코드 예제입니다:
using System.Collections.Generic;
using UnityEngine;
public class ScriptDestroyer : MonoBehaviour
{
// Script 리스트
public List<Script> ObjectScript = new List<Script>();
// 리스트의 모든 Script와 관련된 게임 오브젝트를 파괴하고 리스트를 정리하는 함수
public void DestroyAllAndClear()
{
// 모든 Script의 게임 오브젝트를 파괴
foreach (var script in ObjectScript)
{
if (script != null && script.gameObject != null)
{
Destroy(script.gameObject);
}
}
// 리스트 초기화
ObjectScript.Clear();
// 리스트의 내부 용량 초기화 (선택 사항)
ObjectScript.TrimExcess();
}
}
3. 코드 상세 설명
1) foreach 루프를 활용한 파괴
foreach 루프를 사용해 리스트 내의 모든 Script를 순회하며, 해당 스크립트에 연결된 게임 오브젝트를 Destroy()로 파괴합니다.
- 유효성 체크:
- 스크립트가 null이거나 이미 파괴된 오브젝트를 참조하지 않도록 안전하게 검사합니다.
- 이를 통해 불필요한 예외(Exception)를 방지할 수 있습니다.
- if (script != null && script.gameObject != null)
- Destroy() 사용:
Destroy()는 유니티에서 게임 오브젝트를 파괴하는 함수입니다. 하지만 즉시 메모리에서 제거되지 않고, 다음 프레임에서 제거됩니다. 따라서 Destroy() 이후에는 파괴된 오브젝트를 참조하지 않아야 합니다.
2) 리스트 초기화: Clear()
리스트를 비우기 위해 Clear()를 호출합니다.
- 이 함수는 리스트의 모든 요소를 제거하지만, 내부 메모리 용량(캐패시티)은 그대로 유지합니다.
- 따라서, 큰 리스트의 메모리를 해제하려면 아래의 **TrimExcess()**를 추가로 호출해야 합니다.
3) 메모리 최적화: TrimExcess()
리스트의 내부 메모리 용량을 초기화합니다.
- ObjectScript.TrimExcess();는 리스트의 크기를 현재 사용 중인 요소 수에 맞게 조정합니다.
- 리스트의 크기가 매우 크거나 많은 오브젝트를 다루는 상황에서 메모리 낭비를 줄일 수 있습니다.
4. 추가 최적화 방법: 오브젝트 풀링(Pooling) 활용
만약 리스트에 있는 오브젝트가 자주 생성 및 파괴된다면, "오브젝트 풀링(Pooling)"을 사용하는 것이 좋습니다.
오브젝트 풀링은 미리 생성된 오브젝트를 재활용해 파괴 및 생성 과정을 최소화하는 방식으로, 성능을 크게 향상시킬 수 있습니다.
public void ReturnToPool(GameObject obj)
{
obj.SetActive(false); // 게임 오브젝트 비활성화
pool.Add(obj); // 풀에 반환
}
public GameObject GetFromPool()
{
if (pool.Count > 0)
{
GameObject obj = pool[0];
pool.RemoveAt(0);
obj.SetActive(true); // 활성화 후 반환
return obj;
}
// 풀에 오브젝트가 없으면 새로 생성
GameObject newObj = Instantiate(prefab);
return newObj;
}
5. 최적화된 메모리 관리의 중요성
- 안전성:
- 이미 파괴된 오브젝트를 참조하거나 null 참조 문제를 방지할 수 있습니다.
- 성능 최적화:
- 게임 내 불필요한 메모리 점유를 줄이고, 메모리 릭(Memory Leak)을 예방할 수 있습니다.
- 확장성:
- List와 같은 자료 구조를 효율적으로 관리하여 대규모 오브젝트 관리에도 대응할 수 있습니다.
List<Script>에 저장된 스크립트와 관련된 게임 오브젝트를 효율적으로 파괴하고 메모리를 최적화하는 방법을 살펴보았습니다. 유니티 프로젝트에서는 메모리 관리를 소홀히 하면 성능 저하, 메모리 누수, 그리고 충돌 등의 문제가 발생할 수 있으므로, 항상 효율적인 리소스 관리 방법을 고민해야 합니다.
'GameDev > [Unity]' 카테고리의 다른 글
[유니티]Addressables: LoadAssetAsync와 InstantiateAsync의 차이와 사용 방법 (0) | 2025.01.09 |
---|---|
[유니티]Unity에서 DOTween 사용하기: 초보자를 위한 가이드 (0) | 2024.12.30 |
[유니티]숫자를 문자열로 바꾸는 다양한 방법: ToString() 완벽 정리 (1) | 2024.12.24 |
[유니티]유니티에서 타겟의 Vector3를 기준으로 오브젝트가 바라보게 하는 방법 (1) | 2024.12.18 |
유니티 Transform.LookAt 완벽 가이드: 부드러운 회전과 축 제한 팁 (2) | 2024.12.17 |