5.5 KiB
5.5 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| perf-v8-optimization | V8 Optimization — Hidden class / Inline cache / Hot path | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
V8 Optimization
JIT 친화 코드 = 100x 빠름. Monomorphic > polymorphic > megamorphic. Hidden class 안정 + 같은 type 만 + tight loop. 보통 알고리즘 < V8 hint.
📖 핵심 개념
- Hidden class (Map): object shape — V8 가 cache.
- IC (Inline Cache): 같은 site 같은 type → fast.
- Monomorphic / Polymorphic / Megamorphic.
- Deopt: 다른 type 출현 → JIT 코드 폐기.
💻 코드 패턴
Hidden class 안정
// ❌ 다른 순서 / 다른 필드 = 다른 hidden class
const a = { x: 1 };
a.y = 2;
const b = { y: 2 };
b.x = 1;
// a, b 가 다른 hidden class
// ✅
const a = { x: 1, y: 2 };
const b = { x: 3, y: 4 };
// 같은 hidden class
→ Object literal 시 모든 필드 한 번에. 추가 X.
Monomorphic 함수
// ❌ 다양한 type
function getX(obj) { return obj.x; }
getX({ x: 1 }); // shape A
getX({ x: 1, y: 2 }); // shape B
getX({ x: 1, y: 2, z: 3 }); // shape C
// → polymorphic / megamorphic — 느림
// ✅ 같은 shape 만
class Point { constructor(x, y) { this.x = x; this.y = y; } }
const points = [new Point(1, 2), new Point(3, 4)];
points.forEach(p => p.x); // monomorphic
Class > 동적 object
// ✅ 빠름
class User {
constructor(public id: string, public email: string) {}
}
// ⚠️ 느릴 수 있음
const user = { id, email, age, ...rest };
→ Class 가 hidden class 강제.
Tight loop
// ✅
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
// ⚠️ functional — V8 가 잘 최적화 하지만 일부 case 느림
const sum = arr.reduce((s, x) => s + x, 0);
→ Hot path = 측정 후 결정.
Avoid deopt triggers
// ❌ try-catch 안 hot loop (V8 옛 — 새 V8 는 OK)
function hot() {
try {
for (...) inner();
} catch (e) { ... }
}
// 새 V8 는 try-catch 거의 무 비용.
// ❌ delete (hidden class 변경)
delete obj.x;
// ❌ undefined / null mix
function add(a, b) { return a + b; }
add(1, 2);
add('x', 'y'); // string concat — deopt
TypedArray (대량 숫자)
// ✅
const arr = new Float32Array(1_000_000);
arr[0] = 1.5;
// 빠름, 작은 메모리, GC 압력 적음
// ❌ 일반 array
const arr = new Array(1_000_000).fill(0);
String concatenation
// ✅ 큰 string
const parts: string[] = [];
for (...) parts.push(line);
const result = parts.join('\n');
// ❌
let result = '';
for (...) result += line;
// V8 가 어느 정도 최적화 하지만 array.join 가 안전.
// ✅ 작은 string
const s = `${a} - ${b}`; // 일반 OK
Object 재사용 (allocation 줄이기)
// ❌ 매 iteration object 새로
function process(items) {
for (const it of items) {
const tmp = { x: it.x, y: it.y };
use(tmp);
}
}
// ✅
const tmp = { x: 0, y: 0 };
function process(items) {
for (const it of items) {
tmp.x = it.x;
tmp.y = it.y;
use(tmp);
}
}
⚠️ Mutation 주의 — 라이브러리에 안 맞음.
Inline 작은 함수
// V8 가 작은 함수 자동 inline. 너가 따로 inline 할 필요 X.
// 단 monomorphic 강한 경우.
Map vs Object (key set 자주 변경)
// ✅ Map — 동적 key 안정
const m = new Map();
m.set('a', 1); m.set('b', 2); m.delete('a');
// ❌ object — delete 가 hidden class 변경
const o = {};
o.a = 1; delete o.a;
--trace-deopt (debug)
node --trace-deopt app.js
# 어느 함수가 deopt 됐는지
node --trace-opt app.js
# Optimize / 다시
Hot function 측정
const COUNT = 1_000_000;
const arr = Array.from({ length: COUNT }, (_, i) => i);
const t = performance.now();
for (let i = 0; i < arr.length; i++) hotFn(arr[i]);
console.log('avg:', (performance.now() - t) / COUNT, 'ms');
V8 inspector profiling
node --prof app.js
node --prof-process isolate-*.log > profile.txt
또는 위 (Node profiling) 의 0x / clinic.
Algorithm > Micro-opt
Big O 가 99% 의 답.
O(n²) → O(n log n) = 1000x 빠름.
Monomorphic vs polymorphic = 2-10x.
→ 알고리즘 먼저, micro-opt 마지막.
Bun / Deno
Bun = JSC (Safari engine).
Deno = V8 (Chrome engine).
코드 호환 — engine 별 미세 차이.
🤔 의사결정 기준
| 작업 | 우선순위 |
|---|---|
| Big O | 1순위 |
| Monomorphic / class | 2순위 |
| TypedArray (숫자) | hot loop |
| Allocation 줄이기 | very hot path |
| try-catch / delete | 이젠 무 의미 (V8 modern) |
| Inline / unroll | 측정 후 |
❌ 안티패턴
- Algorithm 무시 + V8 trick: O(n²) 가 V8 trick 으로 안 됨.
- 모든 곳 micro-opt: 가독성 잃음. hot path 만.
- Object shape 매번 다름: deopt.
- Ah-hoc benchmark (1번 측정): warmup 필요. 평균.
- 매 turn V8 update 따라가기: 너무 unstable. 알고리즘 우선.
- Premature optimization: 측정 X 추측.
🤖 LLM 활용 힌트
- Big O 우선. micro-opt 는 hot path 측정 후.
- Monomorphic class > 동적 object.
- TypedArray = 숫자 큰 array.