"매 acquire/release 의 pairing 을 lexical scope 에 강제". 매 file handle, socket, mutex, GPU buffer, DB connection 등 finite resource 의 leak 을 방지하는 discipline. Stroustrup 의 RAII (1980s C++) → Rust 의 ownership/Drop (2015) → Python with / Java try-with-resources / TS using (TC39 Stage 3, 2023) 으로 mainstream language 전반에 확산.
매 핵심
매 resource 종류
Memory: heap allocation, buffer, arena.
Handles: file, socket, pipe, FD limit (Linux 기본 1024).
Bounded concurrency: semaphore 로 N parallel limit.
Cleanup ordering: LIFO (stack) — dependent resource 먼저 release.
💻 패턴
Rust: RAII via Drop
usestd::fs::File;usestd::io::Write;fnwrite_log(msg: &str)-> std::io::Result<()>{letmutf=File::create("/tmp/log.txt")?;// acquire
f.write_all(msg.as_bytes())?;Ok(())// f.drop() automatic — release on scope exit, even on panic
}
TypeScript: using (TC39 explicit resource management, ES2024)
classDbConnectionimplementsDisposable{constructor(publicreadonlyurl: string){/* connect */}query(sql: string){/* ... */}[Symbol.dispose](){/* close */}}functionfetchUser(id: string){usingdb=newDbConnection('postgres://...');returndb.query(`select * from users where id='${id}'`);}// db disposed automatically on return / throw
Python: contextmanager
fromcontextlibimportcontextmanagerimportpsycopg@contextmanagerdefconnection(dsn:str):conn=psycopg.connect(dsn)try:yieldconnfinally:conn.close()withconnection('postgres://...')asc:c.execute('SELECT 1')# c is closed even if execute raises
Go: defer (LIFO)
funcprocessFile(pathstring)error{f,err:=os.Open(path)iferr!=nil{returnerr}deferf.Close()// LIFO — runs even on paniclock:=acquireLock()deferlock.Release()returnparse(f)}
Connection pool (Node + pg)
import{Pool}from'pg';constpool=newPool({max: 20,idleTimeoutMillis: 30_000,connectionTimeoutMillis: 2_000,});asyncfunctiongetUser(id: string){constclient=awaitpool.connect();try{constr=awaitclient.query('SELECT * FROM users WHERE id=$1',[id]);returnr.rows[0];}finally{client.release();// 매 finally 가 critical
}}
Bounded concurrency (semaphore)
importpLimitfrom'p-limit';constlimit=pLimit(10);// max 10 concurrent
constresults=awaitPromise.all(urls.map(url=>limit(()=>fetch(url).then(r=>r.json()))),);
importasyncioasyncdeffetch_with_timeout():asyncwithasyncio.timeout(5.0):asyncwithaiohttp.ClientSession()ass:asyncwiths.get('https://api.example.com')asr:returnawaitr.json()# all three context managers cleanly close on timeout
매 결정 기준
상황
Approach
Rust/C++
RAII via Drop/destructor (default)
TS/JS modern
using + Disposable (TC39 explicit)
Python
with + contextlib
Go
defer (LIFO ordering)
Network connection 다수
Pool + acquire timeout
Concurrent task 수천
Semaphore (p-limit, asyncio.Semaphore)
GPU memory
Explicit eval / del / cudaFree
기본값: 매 lexical scope 기반 (RAII / using / with / defer). 매 manual close 의 X.
언제: 매 server, 매 batch job, 매 GPU inference, 매 long-running daemon — 매 leak 누적이 critical.
언제 X: 매 short-lived script (<1s), 매 throwaway notebook — 매 process exit 이 cleanup.
❌ 안티패턴
Forgotten close: 매 try 만, 매 finally 없음 → leak on exception.
Double-free: 매 close 두 번 → undefined behavior 또는 exception.
Use-after-release: 매 closed connection 재사용 → broken pipe.
Manual ref counting in GC language: 매 reinventing — using/with 사용.
Unbounded pool: 매 max 없음 → DB connection storm 으로 outage.
GPU OOM 무시: 매 eval 없이 lazy graph 누적 → MLX/CUDA OOM.
🧪 검증 / 중복
Verified: Stroustrup The C++ Programming Language; Rust Programming Rust 2e; TC39 Explicit Resource Management proposal (Stage 3, 2024).