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

5.6 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-object-pooling Object Pooling 10_Wiki/Topics verified self
Object Pool
Pool Pattern
Resource Pool
none A 0.9 applied
performance
memory
gamedev
design-pattern
gc
2026-05-10 pending
language framework
cpp-csharp-typescript 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)

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

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

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

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)

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

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