study
레퍼런스 카운트
Date: 2025-12-30 23:51
Update: 2025-12-31 09:40
직접 관리
객체 내부에 참조 카운트 변수를 직접 포함 시키는 방식입니다. AddRef() ,Release()를 통해 카운트를 조절합니다.
장점 :
- 메모리 효율 : shared_ptr과 달리 Control Block 할당이 필요 없어 메모리 파편화가 적습니다.
- 캐시 친화적: 참조 카운트가 객체 데이터와 붙어 있어 CPU 캐시 적중률이 좋습니다.
- 유연성 : `this`포인터 만으로 안전하게 Reference Pointer를 생성할 수 있습니다.
단점:
- 구현 비용: 모든 관리 대상 클래스가 특정 베이스 클래스를 상속 받아야 합니다.
- 순환 참조: Weak Pointer 구현이 까다롭거나 직접 만들어야 하여 순환 참조 해결이 어렵습니다.
사용처: 텍스처, 메쉬, 사운드, 쉐이더 등 리소스
STL(Shared Ptr)
C++ 표준 라이브러리에서 제공 하는 스마트 포인터 입니다. 객체 외부의 별도 제어 블록에서 카운팅을 관리합니다.
작동 원리:
- 포인터가 객체와 제어 블록 두가지를 가리킵니다.
장점:
- 표준화: 구현이 필요 없고 신뢰성이 높습니다.
- 비침입적: `Int`, `struct`, 외부 라이브러리 객체 등 어떤 타입에도 바로 적용 가능합니다.
- Weak Ptr: `weak_ptr` 를 통해 순환 참조 문제를 비교적 쉽게 해결할 수 있습니다.
단점:
- 오버헤드: `make_shared` 를 사용하지않으면 객체와 제어 블록이 따로 할당 되어 캐시 효율이 떨어집니다.
- 스레드 안전 비용: 기본적으로 참조 카운트 조작이 `atomic` 연산이라서, 단일 스레드 게임 로직에서도 불필요한 성능 저하가 발생할 수 있습니다.
- 무거움: 일반 포인터 보다 크기가 2배(객체 포인터 + 제어 블록 포인터)입니다.
Handle
객체의 메모리 주소를 직접 들고 있는 것이 아니라, ID(인덱스 + 버전)을 들고 있고, 필요할 때 시스템을 통해 객체에 접근하는 방식입니다.
작동원리:
- Handle(`Integer`)→ Manger → 실제 객체 포인터 순으로 접근합니다.
장점:
- 댕글링 포인터 해결: 객체가 삭제되어도 핸들은 유효하지 않은 상태가 될 뿐, 크래시가 발생하지 않습니다. 죽었는지 확인이 가능합니다.
- 직렬화: 핸들은 단순 정수형 이므로 네트워크 패킷 전송이나 세이브/로드 저장이 매우 쉽습니다.
- 메모리 재배치: 실제 객체의 메모리 위치가 바뀌어도 핸들 값은 유지 되므로 관리가 용이합니다.
단점:
- 접근 비용: 객체를 쓸 때마다 매니저를 거쳐야 하므로, 직접 포인터 접근 보다 느립니다.
- 구현 난이도: 별도의 핸들 매니저 시스템을 구축해야 합니다.
사용처: 엔티티, 게임 오브젝트, 컴포넌트
| 직접관리(Intrusive) | Shared Ptr(STL) | Handle 방식 | |
|---|---|---|---|
| 성능 | 직접 포인터에 접근 | 약간의 오버헤드 | Look-up 비용 발생 |
| 메모리 효율 | 단일 할당 | 제어 블록 추가 | 테이블 관리 필요 |
| 안전성 | 낮음 | 수명 연장 | 접근 시 검증 |
| 편의성 | 상속 필요 | 즉시 사용 가능 | 시스템 구축 필요 |
| 직렬화/네트워크 | 어려움 | 어려움 | 매우 쉬움 |
| 주요 용도 | 엔진 코어, 리소스 | 툴, UI, 고레벨 로직 | 게임 엔티티, 네트워크 객체 |
undefined
.gif)