--- id: wiki-2026-0508-object-pooling-오브젝트-풀링 title: Object Pooling (오브젝트 풀링) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [오브젝트 풀링, Object Pool Pattern] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [pattern, performance, memory, gc, gamedev] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: agnostic --- # Object Pooling (오브젝트 풀링) ## 매 한 줄 > **"매 expensive object 의 reuse 로 GC pressure + allocation cost 의 회피"**. 매 game loop / hot path / high-frequency event handler 의 standard 의 패턴 — 매 2026 의 game engine (Three.js, Bevy, Unity DOTS), DB connection pool, HTTP keep-alive, worker pool 의 universal 의 pattern. ## 매 핵심 ### 매 3-component - **Pool**: 매 object 의 collection (free list). - **Acquire**: 매 free object 의 dequeue (또는 신규 생성). - **Release**: 매 object 의 reset + enqueue. ### 매 언제 적용 - 매 allocation rate > 10K/sec. - 매 object lifetime 의 짧음 (< 1 frame). - 매 GC pause 의 user-visible (game, real-time). - 매 expensive constructor (DB connect, file open, GPU buffer alloc). ### 매 응용 1. Game particle system — bullet, explosion, enemy. 2. DB connection pool — `pg-pool`, HikariCP. 3. HTTP agent — `http.Agent({ keepAlive: true })`. 4. Web Worker pool — `piscina`. ## 💻 패턴 ### Generic pool (TypeScript) ```typescript class ObjectPool { private free: T[] = []; constructor( private factory: () => T, private reset: (obj: T) => void, initialSize = 0 ) { for (let i = 0; i < initialSize; i++) this.free.push(factory()); } acquire(): T { return this.free.pop() ?? this.factory(); } release(obj: T): void { this.reset(obj); this.free.push(obj); } } ``` ### Three.js Vector3 pool (game loop) ```typescript import { Vector3 } from 'three'; const vec3Pool = new ObjectPool( () => new Vector3(), (v) => v.set(0, 0, 0), 256 ); function updateBullet(b: Bullet, dt: number) { const tmp = vec3Pool.acquire(); tmp.copy(b.velocity).multiplyScalar(dt); b.position.add(tmp); vec3Pool.release(tmp); } ``` ### Particle system pool ```typescript class Particle { position = new Vector3(); velocity = new Vector3(); life = 0; active = false; } class ParticleSystem { private pool: Particle[]; private active: Particle[] = []; constructor(maxParticles: number) { this.pool = Array.from({ length: maxParticles }, () => new Particle()); } spawn(pos: Vector3, vel: Vector3, life: number) { const p = this.pool.pop(); if (!p) return; // pool exhausted p.position.copy(pos); p.velocity.copy(vel); p.life = life; p.active = true; this.active.push(p); } update(dt: number) { for (let i = this.active.length - 1; i >= 0; i--) { const p = this.active[i]; p.life -= dt; if (p.life <= 0) { p.active = false; this.active.splice(i, 1); this.pool.push(p); // return to pool } else { p.position.addScaledVector(p.velocity, dt); } } } } ``` ### DB connection pool (pg) ```typescript import { Pool } from 'pg'; const pool = new Pool({ max: 20, idleTimeoutMillis: 30_000, connectionTimeoutMillis: 2000, }); async function query(sql: string, params: unknown[]) { const client = await pool.connect(); try { return await client.query(sql, params); } finally { client.release(); // ← back to pool } } ``` ### Worker thread pool (piscina) ```typescript import Piscina from 'piscina'; const piscina = new Piscina({ filename: new URL('./worker.js', import.meta.url).href, minThreads: 2, maxThreads: 8, }); const result = await piscina.run({ payload: data }); ``` ### Bounded pool with backpressure ```typescript class BoundedPool { private free: T[] = []; private waiters: ((obj: T) => void)[] = []; private created = 0; constructor( private factory: () => T, private reset: (obj: T) => void, private max: number ) {} async acquire(): Promise { if (this.free.length) return this.free.pop()!; if (this.created < this.max) { this.created++; return this.factory(); } return new Promise((resolve) => this.waiters.push(resolve)); } release(obj: T): void { this.reset(obj); const w = this.waiters.shift(); if (w) w(obj); else this.free.push(obj); } } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Hot path allocation (game loop) | object pool (generic) | | DB / network connection | bounded pool with backpressure | | Heavy CPU task | worker thread pool (piscina) | | Short-lived simple obj (< 1KB) | 매 V8 의 young-gen GC 의 충분 — pool 의 X | | Object 의 reset cost > construct cost | pool 의 X | **기본값**: 매 profile 후 의 적용 — premature pooling 의 X. ## 🔗 Graph - 부모: [[Garbage Collection]] · [[V8 엔진 힙 아키텍처]] - 변형: [[bitECS와 SharedArrayBuffer를 결합한 멀티스레드 고성능 아키텍처]] - 응용: [[InstancedMesh 최적화]] · [[가변적 LOD(Level of Detail) 시스템]] - Adjacent: [[Old_Space|Old Space]] · [[세대 가설(Generational Hypothesis)]] ## 🤖 LLM 활용 **언제**: game loop / real-time pipeline 의 GC pause 회피, expensive resource (DB conn, GPU buffer) 의 reuse. **언제 X**: simple short-lived object — 매 modern GC 의 충분. ## ❌ 안티패턴 - **Reset 의 누락**: 매 stale state 의 leak — 매 security risk (sensitive data). - **Unbounded pool**: 매 memory leak — 매 max size 의 강제. - **Pool 의 lock contention**: 매 multi-thread 의 sync overhead — thread-local pool 의 고려. - **Object 의 over-aliasing**: 매 release 후 의 reference 유지 — use-after-free 의 bug. ## 🧪 검증 / 중복 - Verified (Game Programming Patterns / R. Nystrom, V8 blog, piscina docs). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — TS generic pool, Three.js, piscina 패턴 추가 |