This page was translated from English by the community. Learn more and join the MDN Web Docs community.

View in English Always switch to English

JavaScript์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

C ์–ธ์–ด๊ฐ™์€ ์ €์ˆ˜์ค€ ์–ธ์–ด์—์„œ๋Š”, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด malloc() ๊ณผ free()๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, JavaScript๋Š” ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ ์ž๋™์œผ๋กœ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค(๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜). ์ด๋Ÿฌํ•œ ์ž๋™ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ์ž ์žฌ์  ํ˜ผ๋ž€์˜ ์›์ธ์ด๊ธฐ๋„ ํ•œ๋ฐ, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ์ž˜๋ชป๋œ ์ธ์‹์„ ์‹ฌ์–ด์ค„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ์ƒ์กด์ฃผ๊ธฐ

๋ฉ”๋ชจ๋ฆฌ ์ƒ์กด์ฃผ๊ธฐ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

  1. ํ•„์š”ํ•  ๋•Œ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
  2. ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. (์ฝ๊ธฐ, ์“ฐ๊ธฐ)
  3. ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ๋ชจ๋“  ์–ธ์–ด์—์„œ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„๊ณผ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์€ ์ €์ˆ˜์ค€ ์–ธ์–ด์—์„œ๋Š” ๋ช…์‹œ์ ์ด๋ฉฐ, JavaScript์™€ ๊ฐ™์€ ๋Œ€๋ถ€๋ถ„์˜ ๊ณ ์ˆ˜์ค€ ์–ธ์–ด์—์„œ๋Š” ์•”๋ฌต์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

JavaScript์˜ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น

๊ฐ’ ์ดˆ๊ธฐํ™”

ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ์‹ ๊ฒฝ์„ ์“ธ ํ•„์š”๊ฐ€ ์—†๋„๋ก, JavaScript๋Š” ๊ฐ’์„ ์„ ์–ธํ•  ๋•Œ ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

js
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,
);

ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•œ ํ• ๋‹น

ํ•จ์ˆ˜ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ์ผ์–ด๋‚˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

js
const d = new Date(); // Date ๊ฐœ์ฒด๋ฅผ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น

const e = document.createElement("div"); // DOM ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น

๋ฉ”์†Œ๋“œ๊ฐ€ ์ƒˆ๋กœ์šด ๊ฐ’์ด๋‚˜ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํ• ๋‹นํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

js
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) ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜

์ฐธ๊ณ  : ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋Š” ๋” ์ด์ƒ ์ฐธ์กฐ-์„ธ๊ธฐ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ-์„ธ๊ธฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ '์–ด๋–ค ๋‹ค๋ฅธ ๊ฐ์ฒด๋„ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด'๋ฅผ '๋” ์ด์ƒ ํ•„์š” ์—†๋Š” ๊ฐ์ฒด'๋ผ๊ณ  ์—ฌ๊น๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋ฅผ "๊ฐ€๋น„์ง€"๋ผ ๋ถ€๋ฅด๋ฉฐ, ์ด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š” ๊ฒฝ์šฐ, ์ˆ˜์ง‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ:

js
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' ์†์„ฑ์—๋Š”
// ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์ด ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ์ผ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š”, ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ์ฐธ์กฐํ•˜๋Š” ์†์„ฑ์œผ๋กœ ์ƒ์„ฑ๋˜์–ด ์ˆœํ™˜ ๊ตฌ์กฐ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜๋ฉด ์ด ๋‘ ๊ฐ์ฒด๋Š” ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚˜๊ฒŒ ๋  ๊ฒƒ์ด๋ฉฐ, ๊ทธ ์‹œ์ ์—์„œ ๋‘ ๊ฐ์ฒด๋Š” ๋ถˆํ•„์š”ํ•ด์ง€๋ฏ€๋กœ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋Š” ํšŒ์ˆ˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ์ฐธ์กฐ-์„ธ๊ธฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋‘˜ ๋‹ค ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ๋Œ€์ƒ์œผ๋กœ ํ‘œ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ํ”ํ•œ ์›์ธ์ž…๋‹ˆ๋‹ค.

js
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 ํ—ค๋” ๋“ฑ์„ ํ†ตํ•ด) ์ƒ์—์„œ๋Š” ๋”๋”์šฑ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์šฉํ•œ ํž™ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ตœ๋Œ€๋Ÿ‰์€ ์•„๋ž˜์™€ ๊ฐ™์€ ํ”Œ๋ž˜๊ทธ๋ฅผ ํ†ตํ•ด ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

bash
node --max-old-space-size=6000 index.js

๋˜ํ•œ ํ”Œ๋ž˜๊ทธ๋‚˜ Chrome Debugger๋ฅผ ์‚ฌ์šฉํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

bash
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 (like Symbol.for("key")) ๋˜ํ•œ ๋ณต์‚ฌ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘์ด ๋ถˆ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, Symbol("key")๋กœ ์ƒ์„ฑ๋œ ๊ธฐํ˜ธ๋Š” ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Symbol.iterator์™€ ๊ฐ™์€ Well-known symbols์€ ๊ณ ์ •๋œ ์„ธํŠธ๋กœ ์ œ๊ณต๋˜๋ฉฐ Array.prototype๊ณผ ๊ฐ™์€ ๊ณ ์œ  ๊ฐ์ฒด์™€ ์œ ์‚ฌํ•˜๊ฒŒ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜๋ช… ๋™์•ˆ ๊ณ ์œ ํ•˜๋ฏ€๋กœ ํ‚ค๋กœ๋„ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • WeakMap๊ณผ WeakSet์€ ์ˆœํšŒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Array.from(map.keys()).length์„ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ๊ด€์ฐฐํ•˜๊ฑฐ๋‚˜ ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘ ๋Œ€์ƒ์ด ๋˜์–ด์•ผํ•˜๋Š” ์ž„์˜์˜ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์€ ์ตœ๋Œ€ํ•œ ์˜ํ–ฅ์„ ๋А๋ผ์ง€ ๋ชปํ•˜๋„๋ก ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค).

์ฃผ๋กœ WeakMap๊ณผ WeakSet์„ ์„ค๋ช…ํ•  ๋•Œ, ๋ณดํ†ต ํ‚ค๊ฐ€ ๋จผ์ € ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘๋˜๊ณ  ์ดํ›„ ๊ฐ’ ๋˜ํ•œ ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘๋œ๋‹ค๊ณ  ์•”์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์•„๋ž˜์™€ ๊ฐ™์ด ํ‚ค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฐ’์ด ์žˆ๋Š” ์ผ€์ด์Šค๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

js
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์„ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌํ˜„์ฒด๋กœ ์ƒ๊ฐํ•ด๋ณด๋ฉด:

๊ฒฝ๊ณ  : ์•„๋ž˜๋Š” ํด๋ฆฌํ•„๋„ ์•„๋‹ˆ๊ณ , ์‹ค์ œ ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์— ๊ด€๊ณ„ํ•˜๋Š” ์—”์ง„์˜ ๊ตฌํ˜„์ฒด ๊ตฌ์กฐ์™€๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ‰๋‹ˆ๋‹ค.

js
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์ด ๋˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

js
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๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ด์ œ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

js
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๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.