---
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) |
