JavaScript์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
C ์ธ์ด๊ฐ์ ์ ์์ค ์ธ์ด์์๋, ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ํด malloc()
๊ณผ free()
๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ฉด, JavaScript๋ ๊ฐ์ฒด๊ฐ ์์ฑ๋์์ ๋ ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๊ณ ๋ ์ด์ ํ์ํ์ง ์์ ๋ ์๋์ผ๋ก ํด์ ํฉ๋๋ค(๊ฐ๋น์ง ์ปฌ๋ ์
). ์ด๋ฌํ ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ ์ ์ฌ์ ํผ๋์ ์์ธ์ด๊ธฐ๋ ํ๋ฐ, ๊ฐ๋ฐ์๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ๋ํด ๊ณ ๋ฏผํ ํ์๊ฐ ์๋ค๋ ์๋ชป๋ ์ธ์์ ์ฌ์ด์ค ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ฉ๋ชจ๋ฆฌ ์์กด์ฃผ๊ธฐ
๋ฉ๋ชจ๋ฆฌ ์์กด์ฃผ๊ธฐ๋ ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ๋น์ทํฉ๋๋ค.
- ํ์ํ ๋ ํ ๋นํฉ๋๋ค.
- ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. (์ฝ๊ธฐ, ์ฐ๊ธฐ)
- ๋ ์ด์ ํ์ํ์ง ์์ผ๋ฉด ํด์ ํฉ๋๋ค.
๋ ๋ฒ์งธ ๋ถ๋ถ์ ๋ชจ๋ ์ธ์ด์์ ๋ช ์์ ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฒซ ๋ฒ์งธ ๋ถ๋ถ๊ณผ ๋ง์ง๋ง ๋ถ๋ถ์ ์ ์์ค ์ธ์ด์์๋ ๋ช ์์ ์ด๋ฉฐ, JavaScript์ ๊ฐ์ ๋๋ถ๋ถ์ ๊ณ ์์ค ์ธ์ด์์๋ ์๋ฌต์ ์ผ๋ก ์๋ํฉ๋๋ค.
JavaScript์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
๊ฐ ์ด๊ธฐํ
ํ๋ก๊ทธ๋๋จธ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ์ ๊ฒฝ์ ์ธ ํ์๊ฐ ์๋๋ก, JavaScript๋ ๊ฐ์ ์ ์ธํ ๋ ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํฉ๋๋ค.
const n = 123; // ์ ์๋ฅผ ๋ด๊ธฐ ์ํ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
const s = "azerty"; // ๋ฌธ์์ด์ ๋ด๊ธฐ ์ํ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
const o = {
a: 1,
b: null,
}; // ์ค๋ธ์ ํธ์ ๊ทธ ์ค๋ธ์ ํธ์ ํฌํจ๋ ๊ฐ๋ค์ ๋ด๊ธฐ ์ํ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
// (์ค๋ธ์ ํธ์ฒ๋ผ) ๋ฐฐ์ด๊ณผ ๋ฐฐ์ด์ ๋ด๊ธด ๊ฐ๋ค์ ์ํ ๋ฉ๋ชจ๋ฆฌ ํ ๋น
const a = [1, null, "abra"];
function f(a) {
return a + 2;
} // ํจ์๋ฅผ ์ํ ํ ๋น(ํจ์๋ ํธ์ถ ๊ฐ๋ฅํ ์ค๋ธ์ ํธ)
// ํจ์์ ๋ํ ์ค๋ธ์ ํธ๋ฅผ ๋ด๊ธฐ ์ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํฉ๋๋ค.
someElement.addEventListener(
"click",
() => {
someElement.style.backgroundColor = "blue";
},
false,
);
ํจ์ ํธ์ถ์ ํตํ ํ ๋น
ํจ์ ํธ์ถ์ ๊ฒฐ๊ณผ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ์ผ์ด๋๊ธฐ๋ ํฉ๋๋ค.
const d = new Date(); // Date ๊ฐ์ฒด๋ฅผ ์ํด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น
const e = document.createElement("div"); // DOM ์๋ฆฌ๋จผํธ๋ฅผ ์ํด ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น
๋ฉ์๋๊ฐ ์๋ก์ด ๊ฐ์ด๋ ์ค๋ธ์ ํธ๋ฅผ ํ ๋นํ๊ธฐ๋ ํฉ๋๋ค.
const s = "azerty";
const s2 = s.substr(0, 3); // s2๋ ์๋ก์ด ๋ฌธ์์ด
// JavaScript์์ ๋ฌธ์์ด์ immutable ๊ฐ์ด๊ธฐ ๋๋ฌธ์,
// ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋ก ํ ๋นํ์ง ์๊ณ ๋จ์ํ [0, 3] ์ด๋ผ๋ ๋ฒ์๋ง ์ ์ฅํฉ๋๋ค.
const a = ["ouais ouais", "nan nan"];
const a2 = ["generation", "nan nan"];
const a3 = a.concat(a2);
// a ์ a2 ๋ฅผ ์ด์ด๋ถ์ฌ, 4๊ฐ์ ์์๋ฅผ ๊ฐ์ง ์๋ก์ด ๋ฐฐ์ด
๊ฐ ์ฌ์ฉ
๊ฐ ์ฌ์ฉ์ด๋ ๊ธฐ๋ณธ์ ์ผ๋ก๋ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ๊ณ ์ฐ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๋ณ์๋ ๊ฐ์ฒด ์์ฑ์ ๊ฐ์ ์ฝ๊ณ ์ฐ๊ฑฐ๋ ํจ์ ํธ์ถ ์ ํจ์์ ์ธ์๋ฅผ ์ ๋ฌํ์ฌ ์ํํ ์ ์์ต๋๋ค.
ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ ์ด์ ํ์์์ ๋ ํด์ ํ๊ธฐ
์ด ๋จ๊ณ์์ ๋๋ถ๋ถ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. "ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ ์ด์ ํ์์์ ๋"๋ฅผ ์์๋ด๊ธฐ๊ฐ ๊ฐ์ฅ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ ์์ค ์ธ์ด์์๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์์์ด์ง ๋๋ฅผ ๊ฐ๋ฐ์๊ฐ ์ง์ ๊ฒฐ์ ํ๊ณ ํด์ ํ๋ ๋ฐฉ์์ ์ฌ์ฉํฉ๋๋ค.
JavaScript์ ๊ฐ์ ๊ณ ์์ค ์ธ์ด๋ค์ "๊ฐ๋น์ง ์ฝ๋ ์ (GC)"์ด๋ผ๋ ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ฐฉ๋ฒ์ ์ฌ์ฉํฉ๋๋ค. ๊ฐ๋น์ง ์ฝ๋ ํฐ์ ๋ชฉ์ ์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ์ถ์ ํ๊ณ ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ด ๋ ์ด์ ํ์ํ์ง ์๊ฒ ๋์๋์ง๋ฅผ ํ๋จํ์ฌ ํ์ํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฌํ ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ํ๋ก์ธ์ค๊ฐ ๊ถ๊ทน์ ๋ฐฉ๋ฒ์ ์๋๋๋ค. ์๋ํ๋ฉด ์ด๋ค ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ฌ์ ํ ํ์ํ์ง ์๋์ง๋ฅผ ํ๋จํ๋ ๊ฒ์ ๋น๊ฒฐ์ ์ ๋ฌธ์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ฐ๋น์ง ์ฝ๋ ์
์์์ ์ธ๊ธํ ๊ฒ์ฒ๋ผ "๋ ์ด์ ํ์ํ์ง ์์" ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐพ๋๊ฑด ๋น๊ฒฐ์ ์ ๋ฌธ์ ์ ๋๋ค. ๋ฐ๋ผ์ ๊ฐ๋น์ง ์ปฌ๋ ํฐ๋ค์ ์ด ๋ฌธ์ ์ ๋ํ ์ ํ์ ์ธ ํด๊ฒฐ์ฑ ์ ๊ตฌํํฉ๋๋ค. ์ด ์น์ ์์๋ ์ฃผ์ํ ๊ฐ๋น์ง ์ปฌ๋ ์ ์๊ณ ๋ฆฌ์ฆ๋ค๊ณผ ๊ทธ ํ๊ณ๋ฅผ ์ดํดํ๋๋ฐ ํ์ํ ๊ฐ๋ ์ ์ค๋ช ํฉ๋๋ค.
์ฐธ์กฐ
๊ฐ๋น์ง ์ฝ๋ ์ ์๊ณ ๋ฆฌ์ฆ์ ํต์ฌ ๊ฐ๋ ์ ์ฐธ์กฐ์ ๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋งฅ๋ฝ์์, A๋ผ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํตํด (๋ช ์์ ์ด๋ ์์์ ์ด๋ ) B๋ผ๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ๊ทผํ ์ ์๋ค๋ฉด "B๋ A์ ์ฐธ์กฐ๋๋ค" ๋ผ๊ณ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ชจ๋ JavaScript ์ค๋ธ์ ํธ๋ prototype (implicit reference) (์์์ ์ฐธ์กฐ) ๋ฐ ๊ทธ ๊ฐ์ฒด์ ์์ฑ์ ๋ํ ์ฐธ์กฐ (๋ช ์์ ์ฐธ์กฐ)๊ฐ ์์ต๋๋ค.
์ด ๋งฅ๋ฝ์์ "๊ฐ์ฒด"์ ๊ฐ๋ ์ ์ผ๋ฐ JavaScript ๊ฐ์ฒด์ ํจ์ ๋ฒ์(๋๋ ์ ์ญ ์ดํ ๋ฒ์)๋ฅผ ํฌํจํ์ฌ ๋ ๋๊ฒ ํ์ฅ๋ฉ๋๋ค.
์ฐธ์กฐ-์ธ๊ธฐ(Reference-counting) ๊ฐ๋น์ง ์ฝ๋ ์
์ฐธ๊ณ : ์ต์ ๋ธ๋ผ์ฐ์ ๋ ๋ ์ด์ ์ฐธ์กฐ-์ธ๊ธฐ ๊ฐ๋น์ง ์ฝ๋ ์ ๋ฐฉ์์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
์ฐธ์กฐ-์ธ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ์ฅ ๋จ์ํ๊ฒ ๊ตฌํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ '์ด๋ค ๋ค๋ฅธ ๊ฐ์ฒด๋ ์ฐธ์กฐํ์ง ์๋ ๊ฐ์ฒด'๋ฅผ '๋ ์ด์ ํ์ ์๋ ๊ฐ์ฒด'๋ผ๊ณ ์ฌ๊น๋๋ค. ์ด ๊ฐ์ฒด๋ฅผ "๊ฐ๋น์ง"๋ผ ๋ถ๋ฅด๋ฉฐ, ์ด๋ฅผ ์ฐธ์กฐํ๋ ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ํ๋๋ ์๋ ๊ฒฝ์ฐ, ์์ง์ด ๊ฐ๋ฅํฉ๋๋ค.
์์ :
let x = {
a: {
b: 2,
},
};
// 2๊ฐ์ ๊ฐ์ฒด๊ฐ ์์ฑ๋์์ต๋๋ค. ํ๋์ ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด์ ์์ฑ์ผ๋ก ์ฐธ์กฐ๋ฉ๋๋ค.
// ๋๋จธ์ง ํ๋๋ 'x' ๋ณ์์ ํ ๋น๋์ด ์ฐธ์กฐ๋ฉ๋๋ค.
// ๋ช
๋ฐฑํ๊ฒ, ๊ฐ๋น์ง ์ฝ๋ ์
์ํ๋ ๋ฉ๋ชจ๋ฆฌ๋ ํ๋๋ ์์ต๋๋ค.
let y = x;
// 'y' ๋ณ์๋ ์์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ๋ ๋ฒ์งธ ๋ณ์์
๋๋ค.
x = 1;
// ์ด์ 'y' ๋ณ์๊ฐ ์์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ์ ์ผํ ๋ณ์๊ฐ ๋์์ต๋๋ค.
let z = y.a;
// ์์ ๊ฐ์ฒด์ 'a' ์์ฑ์ ์ฐธ์กฐํ์ต๋๋ค.
// ์ด์ ์ด ๊ฐ์ฒด๋ ๋ ๊ฐ์ ์ฐธ์กฐ๋ฅผ ๊ฐ์ง๋๋ค.
// 'y'๊ฐ ์์ฑ์ผ๋ก ์ฐธ์กฐํ๊ณ 'z'๋ผ๋ ๋ณ์๊ฐ ์ฐธ์กฐํฉ๋๋ค.
y = "mozilla";
// ์ด์ ๋งจ ์ฒ์ 'x' ๋ณ์๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ๊ฐ ์๊ธฐ ๋๋ฌธ์, ๊ฐ๋น์ง ์ปฌ๋ ์
์ด ๊ฐ๋ฅํฉ๋๋ค.
// ๊ทธ๋ฌ๋, ๊ฐ์ฒด์ 'a' ์์ฑ์ด ์ฌ์ ํ 'z' ๋ณ์์ ์ํด ์ฐธ์กฐ๋๋ฏ๋ก
// ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํ ์ ์์ต๋๋ค.
z = null;
// ์ด์ ๋งจ ์ฒ์ 'x' ๋ณ์๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด์ 'a' ์์ฑ์๋
// ์ฐธ์กฐ๊ฐ ์์ผ๋ฏ๋ก ๊ฐ๋น์ง ์ฝ๋ ์
์ด ์ํ๋ ์ ์์ต๋๋ค.
์ํ ์ฐธ์กฐ๋ฅผ ๋ค๋ฃจ๋ ์ผ์๋ ํ๊ณ๊ฐ ์์ต๋๋ค. ๋ค์ ์์ ์์๋, ๋ ๊ฐ์ฒด๊ฐ ์๋ก ์ฐธ์กฐํ๋ ์์ฑ์ผ๋ก ์์ฑ๋์ด ์ํ ๊ตฌ์กฐ๋ฅผ ์์ฑํฉ๋๋ค. ํจ์ ํธ์ถ์ด ์๋ฃ๋๋ฉด ์ด ๋ ๊ฐ์ฒด๋ ์ค์ฝํ๋ฅผ ๋ฒ์ด๋๊ฒ ๋ ๊ฒ์ด๋ฉฐ, ๊ทธ ์์ ์์ ๋ ๊ฐ์ฒด๋ ๋ถํ์ํด์ง๋ฏ๋ก ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ ํ์๋์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ ๊ฐ์ฒด๊ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ๊ณ ์์ผ๋ฏ๋ก, ์ฐธ์กฐ-์ธ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ๋ ๋ค ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ๋์์ผ๋ก ํ์ํ์ง ์์ต๋๋ค. ์ด๋ฌํ ์ํ ์ฐธ์กฐ๋ ๋ฉ๋ชจ๋ฆฌ ๋์์ ํํ ์์ธ์ ๋๋ค.
function f() {
const x = {};
const y = {};
x.a = y; // x๋ y๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
y.a = x; // y๋ x๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
return "azerty";
}
f();
ํ์ํ๊ณ -์ธ๊ธฐ(Mark-and-sweep) ์๊ณ ๋ฆฌ์ฆ
์ด ์๊ณ ๋ฆฌ์ฆ์ "๋ ์ด์ ํ์์๋ ๊ฐ์ฒด"๋ฅผ "๋๋ฌํ ์ ์๋ ๊ฐ์ฒด"๋ก ์ ์ํฉ๋๋ค.
์ด ์๊ณ ๋ฆฌ์ฆ์ "roots" ๋ผ๋ ๊ฐ์ฒด์ ์งํฉ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. JavaScript์์ root๋ ์ ์ญ ๊ฐ์ฒด์ ๋๋ค. ์ฃผ๊ธฐ์ ์ผ๋ก, ๊ฐ๋น์ง ์ฝ๋ ํฐ๋ roots๋ก ๋ถํฐ ์์ํ์ฌ roots๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๋ค, roots๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ๋ ๊ฐ์ฒด๋ค ๋ฑ์ ์ฐพ์ต๋๋ค. roots๋ก ๋ถํฐ ์์ํ์ฌ ๊ฐ๋น์ง ์ฝ๋ ํฐ๋ ๋ชจ๋ ๋๋ฌํ ์ ์๋ ๊ฐ์ฒด๋ค์ ์ฐพ๊ณ , ๋๋ฌํ ์ ์๋ ๋ชจ๋ ๊ฐ์ฒด๋ค์ ์์งํฉ๋๋ค.
์ด ์๊ณ ๋ฆฌ์ฆ์ ์์ ์ฐธ์กฐ-์ธ๊ธฐ ๋ฐฉ์๋ณด๋ค ๊ฐ์ ๋ ํํ๋ผ๊ณ ํ ์ ์๋๋ฐ, ๊ทธ ์ด์ ๋ ์ฐธ์กฐ๊ฐ ์๋ ๊ฐ์ฒด๋ ๋ช ํํ ๋๋ฌํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ํ ์ฐธ์กฐ์์ ๋ณธ ๊ฒ์ฒ๋ผ, ๊ทธ ๋ฐ๋(๋ช ํํ ๋๋ฌํ ์ ์๋ค๋ฉด, ์ฐธ์กฐ๊ฐ ์๋ค)๋ ์ฌ์ค์ด ์๋๋๋ค.
ํ์ฌ ๋ชจ๋ ์ต์ ์์ง์ ํ์ํ๊ณ -์ธ๊ธฐ ๊ฐ๋น์ง ์์ง์ ์ ๊ณตํฉ๋๋ค. JavaScript ๊ฐ๋น์ง ์์ง ํ๋(์ธ๋๋ณ/์ฆ๋ถ์ /๋์์ /๋ณ๋ ฌ์ ๊ฐ๋น์ง ์์ง)์์ ์ง๋ ๋ช ๋ ๊ฐ์ ๋ชจ๋ ๊ฐ์ ๋ค์ ์ด ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํ์ ํตํ ๊ฐ์ ์ด๋ฉฐ, ๊ฐ๋น์ง ์์ง ์๊ณ ๋ฆฌ์ฆ์ด๋ ์ธ์ "๊ฐ์ฒด๊ฐ ํ์ ์๋์ง"์ ๋ํ ์ ์๋ฅผ ๋ฐ์ํ๋ ๋ถ๋ถ์ ์์ด์์ ๊ฐ์ ์ ์๋๋๋ค.
์ด๋ฌํ ์ ๊ทผ๋ฐฉ์์ ์ง์ ์ ์ธ ํจ์ฉ์ ๋ ์ด์ ์ฃผ๊ธฐ๊ฐ ๋ฌธ์ ๊ฐ ๋์ง ์๋๋ค๋ ์ ์ ๋๋ค. ์์ ์ฒซ ์์์์, ํจ์ ํธ์ถ์ด ๋ฆฌํด๋๊ณ ๋์ ๋ ๊ฐ์ ๊ฐ์ฒด๋ค์ ๋ ์ด์ ์ ์ญ ๊ฐ์ฒด์์ ์ฐธ์กฐํ๊ณ ์๋ ์ด๋ค ๋ฆฌ์์ค์์๋ ์ฐธ์กฐํ์ง ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก, ๋ ๊ฐ์ฒด๋ค์ ๊ฐ๋น์ง ์์ง๊ธฐ๊ฐ ๋๋ฌํ ์ ์๋ ๊ฒ์ผ๋ก ํ๋ช ๋๊ณ ํ ๋น๋์๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ฌ๋, ๊ฐ๋น์ง ์์ง์ ์๋์ผ๋ก ์กฐ์ํ ์ ์๋ค๋ ๋ฌธ์ ๊ฐ ๋จ์ต๋๋ค. ์ด๋ค ๊ฒฝ์ฐ์์๋ ์๋์ผ๋ก ์ธ์ , ์ด๋ค ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ฐํํ ์ง ๊ฒฐ์ ํ๋ ๊ฒ์ด ํธ๋ฆฌํ ๋๊ฐ ์์ต๋๋ค. ๊ฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ฐํํ๊ธฐ ์ํด์, ํด๋น ๊ฐ์ฒด๋ ๋ช ์์ ์ผ๋ก ๋๋ฌํ ์ ์๊ฒ ๋์ด์ผ ํฉ๋๋ค. ๋ํ JavaScript์์ ํ๋ก๊ทธ๋๋ฐ์ ์ผ๋ก ๊ฐ๋น์ง ์์ง์ ์์ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ฉฐ, ๋น๋ก ์์ง์ ํ๋๊ทธ๋ฅผ ํตํด์ API๋ฅผ ์ ๊ณตํ ์ง ๋ชฐ๋ผ๋, ์ฝ์ด ์ธ์ด๋จ์์๋ ์ถํ์๋ ์ง์ํ์ง ์์ ๊ฒ์ ๋๋ค.
์์ง์ ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ(memory model) ์ค์ ํ๊ธฐ
JavaScript ์์ง์ ์ฃผ๋ก ๋ฉ๋ชจ๋ฆฌ ๋ชจ๋ธ์ ๋ ธ์ถํ๋ ํ๋๊ทธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์๋ก, Node.js๋ ์ค์ ๊ณผ ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๋๋ฒ๊น ์ ์ํด ๋ด๋ถ๋ฅผ ๊ตฌ์ฑํ๋ V8 ๋ฉ์ปค๋์ฆ์ ๋ ธ์ถํ๋ ์ถ๊ฐ์ ์ธ ์ต์ ๊ณผ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ์ค์ ์ ๋ธ๋ผ์ฐ์ ์์๋ ๋๋ถ๋ถ์ ๋ถ๊ฐ๋ฅํ๊ณ , ์น ํ์ด์ง(HTTP ํค๋ ๋ฑ์ ํตํด) ์์์๋ ๋๋์ฑ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
๊ฐ์ฉํ ํ ๋ฉ๋ชจ๋ฆฌ์ ์ต๋๋์ ์๋์ ๊ฐ์ ํ๋๊ทธ๋ฅผ ํตํด ์ฌ๋ฆด ์ ์์ต๋๋ค:
node --max-old-space-size=6000 index.js
๋ํ ํ๋๊ทธ๋ Chrome Debugger๋ฅผ ์ฌ์ฉํด ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๋ฅผ ๋๋ฒ๊น ํ๊ธฐ ์ํ ๊ฐ๋น์ง ์ปฌ๋ ํฐ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค ์ ์์ต๋๋ค:
node --expose-gc --inspect index.js
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ๋๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ
๋น๋ก JavaScript๊ฐ ๊ฐ๋น์ง ์์ง๊ธฐ API๋ฅผ ์ง์ ์ ์ผ๋ก ๋ ธ์ถํ์ง๋ ์๋๋ผ๋, JavaScript๋ ๊ฐ์ ์ ์ผ๋ก ๊ฐ๋น์ง ์์ง์ ๊ด์ฐฐํ๋ฉฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ธ ์ ์๋ ๋ช ๊ฐ์ง ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
WeakMaps๊ณผ WeakSets
WeakMap
๊ณผ WeakSet
์ ๊ฐ non-weak์ ๋์๋๋ Map
๊ณผ Set
์ API๋ฅผ ๋ชจ๋ฐฉํ ๋ฐ์ดํฐ ๊ตฌ์กฐ์
๋๋ค. WeakMap
์ ํค-๊ฐ ์์ ๋ชจ์์ ์ ๊ณตํ๋ ๋ฐ๋ฉด, WeakSet
์ ์ ์ผํ ๊ฐ๋ค๋ก ์ด๋ค์ง ๋ชจ์์ ์ ๊ณตํฉ๋๋ค. ๊ฐ๊ฐ์ ์ถ๊ฐ, ์ญ์ , ์กฐํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
WeakMap
๊ณผ WeakSet
์ ์ด๋ฆ์ "weakly held" ๊ฐ์ด๋ผ๋ ๊ฐ๋
์์ ๋ฐ์์ต๋๋ค. ๋ง์ฝ x
๊ฐ y
์ ์ํด "weekly held"๋์๋ค๋ผ๋ ์๋ฏธ๋, ๋น๋ก y
๋ฅผ ํตํด x
์ ๊ฐ์ ์ ๊ทผํ ์ ์์ง๋ง, ํ์ํ๊ณ -์ธ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ๋ค๋ฅธ ๊ฒ์ด x
๋ฅผ _strongly hold* ํ๊ณ ์์ง ์์ ์ด์ ๋๋ฌํ ์ ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ์ง ์์ต๋๋ค. ์ฌ๊ธฐ์ ๋
ผ์๋๊ณ ์๋ ๊ฒ์ ์ ์ธํ, ๋๋ถ๋ถ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์ ๋ฌ๋ ๊ฐ์ฒด๋ฅผ strongly holdํ๊ธฐ์ ๊ฐ์ฒด์ ์ธ์ ๋ ์ ๊ทผํ ์ ์์ต๋๋ค. WeakMap
๊ณผ WeakSet
์ ํค๋ ํ๋ก๊ทธ๋จ์ ์ด๋ค ๊ฒ๋ ํค๋ฅผ ์ฐธ์กฐํ์ง ์๋๋ค๋ฉด ๊ฐ๋น์ง ์ฝ๋ ์
๋ ์ ์์ต๋๋ค (WeakMap
์์ ๊ฐ์ ๊ทธ์ดํ ๊ฐ๋น์ง ์ฝ๋ ์
๋ ์ ์์). ์ด ๋ถ๋ถ์ ์๋ ๋ ๊ฐ์ง ํน์ฑ์ ํตํด ๋ณด์ฅ๋ฉ๋๋ค:
WeakMap
๊ณผWeakSet
์ ์ค์ง ๊ฐ์ฒด ๋๋ ๊ธฐํธ๋ง ์ ์ฅํฉ๋๋ค. ๊ทธ ์ด์ ๋ ์ค์ง ๊ฐ์ฒด๋ค๋ง์ด ๊ฐ๋น์ง ์ฝ๋ ํธ๋๊ณ ์์๊ฐ๋ค์ ๋ณต์ฌ๋๊ธฐ์(1 === 1
์ด๋{} !== {}
์ด๊ธฐ์), ์์๊ฐ๋ค์ด ์ฝ๋ ์ ์ ์์ํ ๋จ๋๋ก ํฉ๋๋ค. Registered symbols (likeSymbol.for("key")
) ๋ํ ๋ณต์ฌ๋ ์ ์์ผ๋ฏ๋ก, ๊ฐ๋น์ง ์์ง์ด ๋ถ๊ฐ๋ฅํ์ง๋ง,Symbol("key")
๋ก ์์ฑ๋ ๊ธฐํธ๋ ๊ฐ๋น์ง ์์ง์ด ๊ฐ๋ฅํฉ๋๋ค.Symbol.iterator
์ ๊ฐ์ Well-known symbols์ ๊ณ ์ ๋ ์ธํธ๋ก ์ ๊ณต๋๋ฉฐArray.prototype
๊ณผ ๊ฐ์ ๊ณ ์ ๊ฐ์ฒด์ ์ ์ฌํ๊ฒ ํ๋ก๊ทธ๋จ ์๋ช ๋์ ๊ณ ์ ํ๋ฏ๋ก ํค๋ก๋ ํ์ฉ๋ฉ๋๋ค.WeakMap
๊ณผWeakSet
์ ์ํํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉดArray.from(map.keys()).length
์ ์ฌ์ฉํด ๊ฐ์ฒด์ ์ํ๋ฅผ ๊ด์ฐฐํ๊ฑฐ๋ ๊ฐ๋น์ง ์์ง ๋์์ด ๋์ด์ผํ๋ ์์์ ํค๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค(๊ฐ๋น์ง ์ฝ๋ ์ ์ ์ต๋ํ ์ํฅ์ ๋๋ผ์ง ๋ชปํ๋๋ก ์ํ๋์ด์ผ ํฉ๋๋ค).
์ฃผ๋ก WeakMap
๊ณผ WeakSet
์ ์ค๋ช
ํ ๋, ๋ณดํต ํค๊ฐ ๋จผ์ ๊ฐ๋น์ง ์์ง๋๊ณ ์ดํ ๊ฐ ๋ํ ๊ฐ๋น์ง ์์ง๋๋ค๊ณ ์์ํฉ๋๋ค. ๊ทธ๋ฌ๋, ์๋์ ๊ฐ์ด ํค๋ฅผ ์ฐธ์กฐํ๋ ๊ฐ์ด ์๋ ์ผ์ด์ค๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
const wm = new WeakMap();
const key = {};
wm.set(key, { key });
// ๊ฐ์ด ํค๋ฅผ ์ฐธ์กฐํ๊ธฐ์, `key`๋ ๊ฐ๋น์ง ์ฝ๋ ์
๋์์ด ์๋๋ฉฐ
// ๊ทธ ๊ฐ์ map ์์์ strongly hold๋์ด ์์ต๋๋ค.
๋ง์ฝ key
๊ฐ ์ค์ ์ฐธ์กฐ๋ก ์ ์ฅ๋๋ค๋ฉด, ๋ค๋ฅธ ๊ฐ์ด key
๋ฅผ ์ฐธ์กฐํ์ง ์์๋ ์ํ ์ฐธ์กฐ๋ฅผ ๋ง๋ค๋ฉฐ ํค์ ๊ฐ ๋ชจ๋ ๊ฐ๋น์ง ์์ง ๋์์ด ์๋๋๋ก ํฉ๋๋ค. ๊ทธ ์ด์ ๋ ๋ง์ฝ key
๊ฐ ๊ฐ๋น์ง ์์ง๋๋ฉด, ํน์ ์์ ์ value.key
๋ ์กด์ฌํ์ง ์๋ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ถ์ ์ ํ ์ํฉ์ด ๋ ์ ์์ต๋๋ค. ์ด ์ ์ ์์ ํ๊ธฐ ์ํด, WeakMap
๊ณผ WeakSet
์ ํญ๋ชฉ๋ค์ ์ค์ ์ฐธ์กฐ๊ฐ ์๋๊ณ ํ์ํ๊ณ -์ธ๊ธฐ ๋ฉ์ปค๋์ฆ์ ๋ณด๊ฐ์ ์ธ ephemerons์
๋๋ค. Barros et al.์ ํด๋น ์๊ณ ๋ฆฌ์ฆ์ ๋ํ ํ๋ฅญํ ์์ฝ๋ณธ์ ์ ๊ณตํฉ๋๋ค (4 ํ์ด์ง). ํ ๋ฌธ๋จ์ ์ธ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
Ephemerons์ ํค์ ๊ฐ ๋ชจ๋ weak ๋๋ strong์ผ๋ก ๋ถ๋ฅ๋ ์ ์๋ ์ฝํ ์(weak pairs)์ ๊ฐ์ ํ ๊ฒ์ ๋๋ค. ํค์ ์ฐ๊ฒฐ์ฑ์ ๊ฐ์ ์ฐ๊ฒฐ์ฑ์ ๊ฒฐ์ ํ๋, ๊ฐ์ ์ฐ๊ฒฐ์ฑ์ ํค์ ์ฐ๊ฒฐ์ฑ์ ๊ฒฐ์ ์ง์ง ์์ต๋๋ค. [โฆ] ๊ฐ๋น์ง ์ฝ๋ ์ ์ด ephemerons์ ์ง์ํ ๋, ๊ฐ๋น์ง ์ฝ๋ ์ ์ ํ์ํ๊ธฐ ๋ฐ ์ธ๊ธฐ์ 2๋จ๊ณ๊ฐ ์๋๋ผ 3๋จ๊ณ์ ๊ฑธ์ณ ์งํ๋ฉ๋๋ค.
๋๋ต์ ์ธ ๋ฉํ ๋ชจ๋ธ๋ก, WeakMap
์ ์๋์ ๊ฐ์ ๊ตฌํ์ฒด๋ก ์๊ฐํด๋ณด๋ฉด:
๊ฒฝ๊ณ : ์๋๋ ํด๋ฆฌํ๋ ์๋๊ณ , ์ค์ ๊ฐ๋น์ง ์ฝ๋ ์ ์ ๊ด๊ณํ๋ ์์ง์ ๊ตฌํ์ฒด ๊ตฌ์กฐ์๋ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ๋๋ค.
class MyWeakMap {
#marker = Symbol("MyWeakMapData");
get(key) {
return key[this.#marker];
}
set(key, value) {
key[this.#marker] = value;
}
has(key) {
return this.#marker in key;
}
delete(key) {
delete key[this.#marker];
}
}
์์์์ ๊ฐ์ด, MyWeakMap
๋ ํค ์ฝ๋ ์
์ ์ค์ ๋ก ๋ณด์ ํ์ง ์์ต๋๋ค. MyWeakMap
์ ๋จ์ํ ์ ๋ฌ๋ฐ์ ๊ฐ ๊ฐ์ฒด์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํฉ๋๋ค. ๊ทธ ๊ฐ์ฒด๋ ์ดํ ํ์ํ๊ธฐ-์ธ๊ธฐ๋ฅผ ํตํด ๊ฐ๋น์ง ์ฝ๋ ์
๊ฐ๋ฅํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก, WeakMap
์ ํค๋ฅผ ์ํํ๊ฑฐ๋ WeakMap
์ ํค๋ฅผ ๋ชจ๋ ์ง์ฐ๋ ๊ฒ(clear)์ ๋ถ๊ฐ๋ฅํฉ๋๋ค(clear ์ญ์๋ ์ ์ฒด ํค ์ฝ๋ ์
์ ๋ณด์ ์์กดํฉ๋๋ค).
์ข ๋ ์์ธํ API๋ keyed collections ๊ฐ์ด๋์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
WeakRefs์ FinalizationRegistry
Note:
WeakRef
์FinalizationRegistry
๋ ๊ฐ๋น์ง ์์ง ๊ตฌ์กฐ์ ๋ํ ์ง์ ์ ์ธ ๋ด๋ถ ํ์์ ์ ๊ณตํฉ๋๋ค. ๋ฐํ์ ์๋งจํฑ์ ์์ ํ ๋ณด์ฅ๋ ์ ์๊ธฐ์ ๊ฐ๋ฅํ๋ฉด ์ฌ์ฉํ์ง ์๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๊ฐ์ด ๊ฐ์ฒด์ธ ๋ชจ๋ ๋ณ์๋ค์ ํด๋น ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ์
๋๋ค. ๊ทธ๋ฌ๋, ๊ทธ๋ฌํ ์ฐธ์กฐ๋ "strong" ํฉ๋๋ค. ๊ทธ๋ฐ ๋ณ์๊ฐ ์๋ค๋ฉด ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ๊ฐ์ฒด๋ฅผ ๋งํนํ๋ ๊ฒ์ ๋ง์ต๋๋ค. WeakRef
๋ ๊ฐ์ฒด์ ๋ํ "weak reference" ๋ก ์ค๋ธ์ ํธ๊ฐ ๊ฐ๋น์ง ์์ง๋ ์ ์๋๋ก ํ๋ ๋์์ ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ ๋์ ์ปจํ
์ธ ์ ์ ๊ทผํ๋ ๊ฒ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
WeakRef
์ ํ ๊ฐ์ง ์ฌ์ฉ ์ฌ๋ก๋ ๋ฌธ์์ด URL์ ํฐ ๊ฐ์ฒด์ ๋งคํํ๋ ์บ์์์คํ
์
๋๋ค. ์ด๋ฐ ๋ชฉ์ ์ ์ํด WeakMap
๋ฅผ ์ฌ์ฉํ ์๋ ์๋๋ฐ, ๊ทธ ์ด์ ๋ WeakMap
๊ฐ์ฒด๋ weakly held์ธ "keys" ๋ฅผ ๊ฐ์ง๋ "values" ์ ๊ทธ๋ ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ง์ฝ ํค์ ์ ๊ทผํ๋ฉด, ํญ์ ๊ฒฐ์ ์ ์ผ๋ก ๊ฐ์ ์ป์ต๋๋ค (ํค์ ์ ๊ทผํ ์ ์๋ค๋ ๊ฒ์ด ํค๊ฐ ์์ง ์กด์ฌํ๋ค๋ ๊ฒ์ ์๋ฏธํ๊ธฐ ๋๋ฌธ์). ์ด ๋ถ๋ถ์์, ํค์ ์ ๊ทผ ์ undefined
๋ฅผ ์ป๋ ๊ฒ์ (๋ง์ฝ ์์ํ ๊ฐ๋ ๋ฉ๋ชจ๋ฆฌ ์์ ์กด์ฌํ์ง ์๋๋ค๋ฉด) ๋ค์ ๊ณ์ฐํ๋ฉด ๋๊ธฐ์ ๊ด์ฐฎ์ผ๋, ์ฐ๋ฆฌ๋ ๋๋ฌํ ์ ์๋ ๊ฐ์ฒด๊ฐ ์บ์ ์์์ ์กด์ฌํ๊ธฐ๋ ์ํ์ง ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์, ์ฐ๋ฆฌ๋ ์ผ๋ฐ์ ์ธ Map
์ ๊ฐ๊ฐ์ ๊ฐ์ด ๊ฐ์ฒด์ ์ค์ ๊ฐ์ด ์๋ WeakRef
์ด ๋๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
function cached(getter) {
// ๋ฌธ์์ด URL๊ณผ ๊ฒฐ๊ณผ๊ฐ์ WeakRefs๋ฅผ ์ฐ๊ฒฐํ๋ Map
const cache = new Map();
return async (key) => {
if (cache.has(key)) {
return cache.get(key).deref();
}
const value = await getter(key);
cache.set(key, new WeakRef(value));
return value;
};
}
const getImage = cached((url) => fetch(url).then((res) => res.blob()));
FinalizationRegistry
๋ ๊ฐ๋น์ง ์์ง์ ๊ด์ฐฐํ๊ธฐ ์ํด ๋์ฑ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. FinalizationRegistry
๋ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ๊ณ ๊ฐ๋น์ง ์์ง๋์์ ๋ ์๋ฆผ์ ๋ฐ์ ์ ์๋๋ก ํฉ๋๋ค. ์์๋ก, ์์ ์์๋ก ์์ฑ๋ ์บ์ ์์คํ
์์, ๊ฐ์ฒด๊ฐ ์ค์ ๊ฐ์ ๋ณด์ ํ๊ณ ์๋์ง ์ฌ๋ถ์ ์๊ด์์ด WeakRef
์ค์ ๊ฐ์ด ๊ฐ๋น์ง ์ฝ๋ ์
๋์์ด ๋ฉ๋๋ค. ๋ํ ์๊ฐ์ด ํ๋ฅด๋ฉฐ Map
์ ๋ค๋์ ์๋ฏธ์๋ ํญ๋ชฉ๋ค์ ์ถ์ ํ๊ฒ ๋ฉ๋๋ค. FinalizationRegistry
๋ฅผ ์ฌ์ฉํ์ฌ ์๋์ ๊ฐ์ด ํด์ ๋ฅผ ํ ์ ์์ต๋๋ค.
function cached(getter) {
// ๋ฌธ์์ด URL๊ณผ ๊ฒฐ๊ณผ๊ฐ์ WeakRefs๋ฅผ ์ฐ๊ฒฐํ๋ Map
const cache = new Map();
// ๊ฐ์ด ๊ฐ๋น์ง ์์ง๋ ๋๋ง๋ค, ์บ์์ ํค๊ฐ ์ธ์์ธ ์ฝ๋ฐฑ์ด ํธ์ถ๋์ด
// ์บ์ ํญ๋ชฉ์ ์ ๊ฑฐํ ์ ์๋๋ก ํจ
const registry = new FinalizationRegistry((key) => {
// Note: WeakRef๊ฐ ์ ๋ง๋ก ๋น์๋์ง ํ
์คํธํ๋ ๊ฒ์ด ๋งค์ฐ ์ค์ํฉ๋๋ค.
// ๊ทธ๋ฌ์ง ์๋๋ค๋ฉด, ์ฝ๋ฐฑ์ด ์๋ก์ด ๊ฐ์ฒด๊ฐ ์ด ํค๋ก ์ถ๊ฐ๋ ์ดํ ํธ์ถ๋๊ณ
// ์๋กญ๊ฒ ์์ฑ๋ ๋ฉ๋ชจ๋ฆฌ ์์ ์ค๋ธ์ ํธ๊ฐ ์ญ์ ๋ ์ ์์ต๋๋ค.
if (!cache.get(key)?.deref()) {
cache.delete(key);
}
});
return async (key) => {
if (cache.has(key)) {
return cache.get(key).deref();
}
const value = await getter(key);
cache.set(key, new WeakRef(value));
registry.register(value, key);
return value;
};
}
const getImage = cached((url) => fetch(url).then((res) => res.blob()));
์ฑ๋ฅ๊ณผ ๋ณด์์ ์ธก๋ฉด์์, ์ ํํ ์ด๋ ์์ ์ ์ฝ๋ฐฑ์ด ํธ์ถ๋ ์ง, ๋ฐ๋์ ํธ์ถ๋ ์ง ๋ณด์ฅํ ์ ์์ต๋๋ค. FinalizationRegistry
๋ ์ค์ง ์ค์ํ์ง ์์ ํด์ ๋ฅผ ์ํด์๋ง ์ฌ์ฉ๋์ด์ผ ํฉ๋๋ค. ์ด ๋ฐ์๋ ํญ์ finally
๋ธ๋ก์ ์ํํ๋ try...finally
์ ๊ฐ์ ์ข ๋ ๊ฒฐ์ ์ ์ธ ๋ฆฌ์์ค ๊ด๋ฆฌ ๋ฐฉ์์ด ์์ต๋๋ค. WeakRef
์ FinalizationRegistry
์ ์์ ํ ์ฅ์๊ฐ ์คํ๋๋ ํ๋ก๊ทธ๋จ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ์ต์ ํ๋ฅผ ์ํด ์กด์ฌํฉ๋๋ค.
WeakRef
์ FinalizationRegistry
๋ฅผ ํตํด ๊ฐ๊ฐ์ ์์ธํ API๋ฅผ ์ถ๊ฐ์ ์ผ๋ก ํ์ธํ์ค ์ ์์ต๋๋ค.