Files
2nd/10_Wiki/Topics/Architecture/Object_Pooling.md
T
2026-05-10 22:08:15 +09:00

186 lines
5.6 KiB
Markdown

---
id: wiki-2026-0508-object-pooling
title: Object Pooling
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Object Pool, Pool Pattern, Resource Pool]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [performance, memory, gamedev, design-pattern, gc]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: cpp-csharp-typescript
framework: unity-unreal
---
# Object Pooling
## 매 한 줄
> **"매 expensive-to-create object를 미리 만들어두고 재사용하여 alloc/free latency · GC pressure를 제거."**. 1990s 게임에서 bullet/particle GC spike 회피로 시작. 2026 현재 Unity `ObjectPool<T>`, Unreal pooling subsystem, .NET `ArrayPool<T>`, Netty `Recycler` 등 plat-form 표준.
## 매 핵심
### 매 동작 원리
1. Pool이 N개 instance 미리 alloc.
2. `acquire()` → free list에서 pop.
3. 사용 후 `release()` → reset 후 free list에 return.
4. Pool 부족 시 grow (또는 block / fail).
### 매 적합한 대상
- 매 alloc cost 큼 (network connection, thread, GPU buffer).
- 매 빈번한 short-lived alloc (bullet, particle, packet).
- 매 size predictable.
- 매 reset 가능 (no permanent dirty state).
### 매 응용
1. Game — bullets, enemies, particles, audio sources.
2. Networking — DB connection pool (HikariCP), HTTP client (Apache).
3. Rendering — command buffer pool, descriptor set pool (Vulkan).
## 💻 패턴
### C# Unity ObjectPool (2026 standard)
```csharp
using UnityEngine.Pool;
public class BulletSpawner : MonoBehaviour {
[SerializeField] Bullet prefab;
IObjectPool<Bullet> pool;
void Awake() {
pool = new ObjectPool<Bullet>(
createFunc: () => Instantiate(prefab),
actionOnGet: b => b.gameObject.SetActive(true),
actionOnRelease: b => b.gameObject.SetActive(false),
actionOnDestroy: b => Destroy(b.gameObject),
collectionCheck: true,
defaultCapacity: 64,
maxSize: 512);
}
public void Fire(Vector3 pos, Vector3 dir) {
var b = pool.Get();
b.Init(pos, dir, onExpire: () => pool.Release(b));
}
}
```
### C++ template pool with free-list
```cpp
template<typename T, size_t N>
class ObjectPool {
alignas(T) std::byte storage[N * sizeof(T)];
std::array<T*, N> free_list;
size_t free_top = N;
public:
ObjectPool() {
for (size_t i = 0; i < N; ++i)
free_list[i] = reinterpret_cast<T*>(storage + i * sizeof(T));
}
template<typename... Args>
T* acquire(Args&&... args) {
if (free_top == 0) return nullptr;
T* p = free_list[--free_top];
return new (p) T(std::forward<Args>(args)...);
}
void release(T* p) {
p->~T();
free_list[free_top++] = p;
}
};
```
### TypeScript pool for Web/Node
```typescript
class ObjectPool<T> {
private free: T[] = [];
constructor(
private factory: () => T,
private reset: (t: T) => void,
initial = 0,
) {
for (let i = 0; i < initial; i++) this.free.push(factory());
}
acquire(): T {
return this.free.pop() ?? this.factory();
}
release(t: T) {
this.reset(t);
this.free.push(t);
}
}
// Vector2 pool example
const v2Pool = new ObjectPool<{x:number,y:number}>(
() => ({x:0,y:0}),
v => { v.x = 0; v.y = 0; },
256);
```
### .NET ArrayPool — GC-friendly buffer reuse
```csharp
byte[] buf = ArrayPool<byte>.Shared.Rent(4096);
try {
int n = await stream.ReadAsync(buf, 0, buf.Length);
Process(buf.AsSpan(0, n));
} finally {
ArrayPool<byte>.Shared.Return(buf, clearArray: true);
}
```
### Connection pool (HikariCP idiom in Java)
```java
HikariConfig cfg = new HikariConfig();
cfg.setJdbcUrl("jdbc:postgres://...");
cfg.setMaximumPoolSize(20);
cfg.setIdleTimeout(30_000);
HikariDataSource ds = new HikariDataSource(cfg);
try (Connection c = ds.getConnection(); // ← acquire
PreparedStatement s = c.prepareStatement("...")) {
s.executeQuery();
} // ← release on close()
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| GC spike from short-lived alloc | object pool |
| Network/DB resource | connection pool |
| Render commands | per-frame pool, reset on frame end |
| Variable size buffer | ArrayPool / segregated pool |
| Single-threaded game | simple stack pool |
| Multi-threaded | ConcurrentBag / lock-free pool |
**기본값**: 매 platform 제공 pool 사용 (Unity ObjectPool, ArrayPool, HikariCP) — 매 직접 구현 회피.
## 🔗 Graph
- 부모: [[Memory_Management]] · [[Design_Patterns]]
- 변형: [[Connection_Pool]] · [[Thread_Pool]] · [[Free_List]]
- 응용: [[Game_Loop]] · [[Particle_Systems]] · [[Garbage_Collection]]
- Adjacent: [[Old_Space]] · [[Generational_Hypothesis]] · [[Memory_Leaks]]
## 🤖 LLM 활용
**언제**: GC pressure visible (frame spike), expensive resource creation, predictable churn rate.
**언제 X**: long-lived object, unique-per-instance state, alloc rate 낮음 — 매 premature opt.
## ❌ 안티패턴
- **Forget release**: 매 leak — `using`/`try-finally`/RAII.
- **Use after release**: 매 use-after-free 등가 — generational handle 사용.
- **Dirty state carry-over**: 매 reset 누락 — bug.
- **Unbounded growth**: 매 maxSize 없음 → OOM.
- **Premature pooling**: 매 GC가 충분히 빠른 경우 — measure first.
## 🧪 검증 / 중복
- Verified (Game Programming Patterns by Nystrom 2014, Unity docs 2026, .NET ArrayPool source, HikariCP).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Object pooling pattern (4 lang impls + decision matrix) |