** ๐Ÿ“Œ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์‹ฌํ™”**

๐Ÿ“Œ ์ •์˜

์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋ฐ๋„ GC์— ์˜ํ•ด ํ•ด์ œ๋˜์ง€ ์•Š๊ณ  ๊ณ„์† ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„์žˆ๋Š” ๋ฐ์ดํ„ฐ


๐Ÿ”ฅ ์ฃผ์š” ์›์ธ ์‹ฌํ™” ์ •๋ฆฌ

์›์ธ ์„ค๋ช… ์‹ค์ˆ˜ ํŒจํ„ด
์ „์—ญ ๋ณ€์ˆ˜ ์ „์—ญ ์ฐธ์กฐ๋Š” ์•ฑ ์ข…๋ฃŒ ์ „๊นŒ์ง€ ํ•ด์ œ X window.leak = ...
ํด๋กœ์ € ๋‚ด๋ถ€ ์ฐธ์กฐ ์™ธ๋ถ€ ํ•จ์ˆ˜ ์Šค์ฝ”ํ”„ ์ฐธ์กฐ ์œ ์ง€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด๋ถ€์—์„œ ํด๋กœ์ €
DOM ์š”์†Œ ์ฐธ์กฐ DOM ์‚ญ์ œํ–ˆ๋Š”๋ฐ ์ฐธ์กฐ ๋ณ€์ˆ˜ ์œ ์ง€ let btn = document.getElementById() ํ›„ DOM ์‚ญ์ œ ์•ˆ ํ•จ
ํƒ€์ด๋จธ setInterval โ†’ clearInterval ๋ˆ„๋ฝ ์ฃผ๊ธฐ์  ํ•จ์ˆ˜ โ†’ ํŽ˜์ด์ง€ ์ด๋™ํ•ด๋„ ๊ณ„์† ๋™์ž‘
์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ removeEventListener ์•ˆ ํ•จ Single Page App์—์„œ ์ž์ฃผ ๋ฐœ์ƒ

โœ… ์‹ค๋ฌด ๋ฐฉ์ง€ ์˜ˆ์ œ

// BAD
let leak = [];
document.querySelector('#btn').addEventListener('click', function handler() {
  leak.push(new Array(100000).fill('*'));
});

// GOOD
const btn = document.querySelector('#btn');
function handler() {
  leak.push(new Array(100000).fill('*'));
}
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);

๐Ÿš€ DevTools๋กœ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๊ฒ€์ถœ

  1. Memory โ†’ Heap Snapshot โ†’ GC ๊ฐ•์ œ ์‹คํ–‰
  2. Detached DOM Tree ํ™•์ธ
  3. Object โ†’ Retainers Chain โ†’ ๋ˆ„์ˆ˜๋œ ์ฐธ์กฐ ํ™•์ธ
  4. ์‹ค์ œ ์›์ธ (ํด๋กœ์ €, DOM ์ฐธ์กฐ ๋“ฑ) ์ถ”์  ๊ฐ€๋Šฅ

๐ŸŒณ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ์ƒ ํ๋ฆ„ ๋„์‹ํ™”

[ DOM ์š”์†Œ ]
     โ†“
[ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ, ํด๋กœ์ €์—์„œ ์ฐธ์กฐ ]
     โ†“
[ ์š”์†Œ ์‚ญ์ œ โ†’ ์ฐธ์กฐ ๋‚จ์Œ ]
     โ†“
[ GC ๋ถˆ๊ฐ€ โ†’ ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€ ]


2๏ธโƒฃ ๐ŸŽฏ ๋ฆฌํ”Œ๋กœ์šฐ & ๋ฆฌํŽ˜์ธํŠธ ์ตœ์ ํ™” ์‹ฌํ™”

๐Ÿ“Œ ์ •ํ™•ํ•œ ์ฐจ์ด

์šฉ์–ด ์˜๋ฏธ ์„ฑ๋Šฅ ์˜ํ–ฅ
Reflow (Layout) DOM ๊ตฌ์กฐ ๋ณ€๊ฒฝ โ†’ ๋ ˆ์ด์•„์›ƒ ์žฌ๊ณ„์‚ฐ ํฌ๋‹ค (ํŠธ๋ฆฌ ์ „์ฒด ์˜ํ–ฅ)
Repaint ์ƒ‰์ƒ/ํฐํŠธ ๋“ฑ ์‹œ๊ฐ์  ์†์„ฑ ๋ณ€๊ฒฝ ์ƒ๋Œ€์  ๋‚ฎ์Œ

๐Ÿšจ Reflow ๋ฐœ์ƒ ํŠธ๋ฆฌ๊ฑฐ ์‹ฌํ™”

ํŠธ๋ฆฌ๊ฑฐ ์„ค๋ช…
DOM ์‚ฝ์ž…/์‚ญ์ œ .appendChild(), .remove()
ํด๋ž˜์Šค ์ถ”๊ฐ€/์‚ญ์ œ .classList.add()
offsetWidth, getBoundingClientRect ์ ‘๊ทผ ๊ฐ•์ œ Reflow ๋ฐœ์ƒ!
์œˆ๋„์šฐ ๋ฆฌ์‚ฌ์ด์ฆˆ, ํฐํŠธ ๋ณ€๊ฒฝ ๋“ฑ ย 

๐Ÿ› ๏ธ ์ตœ์ ํ™” ์ „๋žต

๋ฐฉ๋ฒ• ์„ค๋ช…
DocumentFragment ๋‹ค์ˆ˜ DOM ์กฐ์ž‘ โ†’ ํ•œ ๋ฒˆ์— ์‚ฝ์ž…
batch ์ฒ˜๋ฆฌ ์Šคํƒ€์ผ ๋ณ€๊ฒฝ ํ•œ ๋ฒˆ์—
requestAnimationFrame ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ตœ์ ํ™”
GPU ๊ฐ€์†(css transform, opacity) Reflow ํ”ผํ•˜๊ณ  Repaint๋งŒ ์œ ๋„

โŒ ์ž˜๋ชป๋œ ์˜ˆ์ œ:

for (let i = 0; i < 1000; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  document.body.appendChild(item); // Reflow 1000๋ฒˆ ๋ฐœ์ƒ
}

โœ… ๊ฐœ์„  ์˜ˆ์ œ:

const frag = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const item = document.createElement('li');
  item.textContent = `Item ${i}`;
  frag.appendChild(item);
}
document.body.appendChild(frag); // Reflow 1๋ฒˆ


3๏ธโƒฃ ๐Ÿ› ๏ธ ํฌ๋กฌ DevTools ๊ณ ๊ธ‰ ๋””๋ฒ„๊น…

๐Ÿ“Œ ํ•„์ˆ˜ ํƒญ & ์‹ค๋ฌด ํฌ์ธํŠธ

ํƒญ ์‚ฌ์šฉ๋ฒ•
Performance FPS Drop ์›์ธ, Layout Shifts ํ™•์ธ
Memory โ†’ Leak ๋ถ„์„ Snapshot โ†’ Detached DOM/Closure ์ถ”์ 
Sources โ†’ Breakpoints ์กฐ๊ฑด๋ถ€, DOM ๋ณ€๊ฒฝ ์‹œ, XHR ์š”์ฒญ ์‹œ ์ค‘๋‹จ ๊ฐ€๋Šฅ
Network ์š”์ฒญ/์‘๋‹ต ํ—ค๋”, ์บ์‹œ ์ „๋žต ํ™•์ธ
Application ์ฟ ํ‚ค, Storage, Service Worker ํ™•์ธ

๐Ÿš€ ์‹ค์ „ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… ์˜ˆ์‹œ

  1. Performance โ†’ Long Task (๋นจ๊ฐ„์ƒ‰) ํ™•์ธ
  2. ํ•ด๋‹น Task โ†’ ํ•จ์ˆ˜ ํ™•์ธ โ†’ ์Šคํฌ๋กค ๋ ‰ ์›์ธ pinpoint
  3. Memory โ†’ Heap ๋น„๊ต, ๋ˆ„์ˆ˜ ์›์ธ ์ฐพ๊ธฐ


4๏ธโƒฃ ๐Ÿ” XSS & CSRF ์‹ฌํ™”


๐Ÿฆ  XSS ์ข…๋ฅ˜๋ณ„ ์˜ˆ์ œ

์œ ํ˜• ์„ค๋ช… ์˜ˆ์‹œ
Stored XSS DB์— ์Šคํฌ๋ฆฝํŠธ ์ €์žฅ โ†’ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž ๋…ธ์ถœ ๋Œ“๊ธ€์— <script>alert(1)</script>
Reflected XSS URL์— ์‚ฝ์ž… โ†’ ์ฆ‰์‹œ ์‹คํ–‰ ?search=<script>alert(1)</script>
DOM-based XSS JS๊ฐ€ innerHTML๋กœ ๋ฐ”๋กœ ์‚ฝ์ž… element.innerHTML = userInput;

โœ… CSP ์ ์šฉ ์‹ค๋ฌด ์˜ˆ์ œ

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; object-src 'none';">


๐Ÿฆ  CSRF ๊ตฌ์กฐ ์‹œ๊ฐํ™”

User ๋กœ๊ทธ์ธ โ†’ ๊ณต๊ฒฉ ์‚ฌ์ดํŠธ ์ ‘์† โ†’
<img src="https://bank.com/transfer?amount=1000"> โ†’
์ฟ ํ‚ค ์ž๋™ ํฌํ•จ โ†’ ์š”์ฒญ ์กฐ์ž‘ ์„ฑ๊ณต

โœ… ์‹ค๋ฌด ๋ฐฉ์–ด: Token + SameSite

Set-Cookie: session=abc; SameSite=Strict; Secure
  1. ์„œ๋ฒ„ โ†’ ๋žœ๋ค CSRF Token ๋ฐœ๊ธ‰
  2. ํผ/ํ—ค๋”์— ํฌํ•จ โ†’ ์„œ๋ฒ„ ๊ฒ€์ฆ
  3. SameSite + HTTPS ํ•„์ˆ˜


๐Ÿง  ๊ธฐ์ˆ  ๋ฉด์ ‘ ๋Œ€๋น„ ์ดˆ๊ณ ๊ธ‰ ์š”์•ฝ

์งˆ๋ฌธ ํ•ต์‹ฌ ๋‹ต๋ณ€
๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์›์ธ? ์ „์—ญ ๋ณ€์ˆ˜, DOM ์ฐธ์กฐ, ํด๋กœ์ €, ์ด๋ฒคํŠธ ๋ฏธ์ œ๊ฑฐ, ํƒ€์ด๋จธ
๋ฆฌํ”Œ๋กœ์šฐ vs ๋ฆฌํŽ˜์ธํŠธ? ๋ ˆ์ด์•„์›ƒ ์žฌ๊ณ„์‚ฐ โ†’ ์„ฑ๋Šฅ ์˜ํ–ฅ ํผ / ์ƒ‰์ƒ, ๊ธ€๊ผด ๋“ฑ
DevTools Memory์—์„œ ๋ˆ„์ˆ˜ ์ฐพ๊ธฐ? Heap Snapshot โ†’ Detached DOM, Retainers Chain ๋ถ„์„
XSS ๋ฐฉ์–ด๋ฒ•? ์ž…๋ ฅ ๊ฒ€์ฆ, ์ด์Šค์ผ€์ดํ”„, CSP
CSRF ๋ฐฉ์–ด๋ฒ•? Token ๊ฒ€์ฆ, SameSite ์ฟ ํ‚ค, CORS, HTTPS

โœ… ์ข…ํ•ฉ์ฝ”๋“œ ์˜ˆ์ œ

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>๊ณ ๊ธ‰ ์„ฑ๋Šฅ ์ตœ์ ํ™” & ๋ณด์•ˆ ์‹ค์Šต ๐Ÿš€</title>
  <style>
    .output {
      width: 100%;
      min-height: 50px;
      border: 1px solid #333;
      margin-top: 10px;
      padding: 10px;
      background-color: #f9f9f9;
    }
  </style>
</head>
<body>
  <h1>๐Ÿ“š ์„ฑ๋Šฅ ์ตœ์ ํ™” & ๋ณด์•ˆ ์‹ค์Šต</h1>
  
  <h3>1๏ธโƒฃ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€</h3>
  <button id="btnMemoryLeak">๐Ÿ” ์‹คํ–‰</button>
  <div id="output1" class="output"></div>

  <h3>2๏ธโƒฃ ๋ฆฌํ”Œ๋กœ์šฐ & ๋ฆฌํŽ˜์ธํŠธ ์ตœ์ ํ™”</h3>
  <button id="btnReflow">โšก ์‹คํ–‰</button>
  <div id="output2" class="output"></div>

  <h3>3๏ธโƒฃ ํฌ๋กฌ DevTools ํ™œ์šฉ</h3>
  <button id="btnDevTools">๐Ÿ›  ์‹คํ–‰</button>
  <div id="output3" class="output"></div>

  <h3>4๏ธโƒฃ XSS & CSRF ๋ฐฉ์–ด</h3>
  <button id="btnSecurity">๐Ÿ” ์‹คํ–‰</button>
  <div id="output4" class="output"></div>

  <script>
    /*****************************
    1๏ธโƒฃ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€
    *****************************/
    document.getElementById("btnMemoryLeak").addEventListener("click", function() {
      let element = document.createElement("div");
      element.textContent = "โœ… ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์˜ˆ์ œ ์‹คํ–‰!";
      document.body.appendChild(element);
      
      // ๐Ÿ”ด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€: ํƒ€์ด๋จธ ์ข…๋ฃŒ ํ›„ ์š”์†Œ ์ œ๊ฑฐ
      setTimeout(() => {
        document.body.removeChild(element); 
      }, 2000);
      
      document.getElementById("output1").textContent = "๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ: DOM ์š”์†Œ ์ž๋™ ์ œ๊ฑฐ";
    });

    /*****************************
    2๏ธโƒฃ ๋ฆฌํ”Œ๋กœ์šฐ & ๋ฆฌํŽ˜์ธํŠธ ์ตœ์ ํ™”
    *****************************/
    document.getElementById("btnReflow").addEventListener("click", function() {
      const frag = document.createDocumentFragment();
      
      for (let i = 0; i < 1000; i++) {
        const div = document.createElement("div");
        div.textContent = `Item ${i}`;
        frag.appendChild(div);
      }
      
      document.body.appendChild(frag); // ๐Ÿš€ Reflow ์ตœ์†Œํ™”
      document.getElementById("output2").textContent = "Reflow ์ตœ์ ํ™” ์™„๋ฃŒ!";
    });

    /*****************************
    3๏ธโƒฃ ํฌ๋กฌ DevTools ํ™œ์šฉ
    *****************************/
    document.getElementById("btnDevTools").addEventListener("click", function() {
      console.log("Performance ํƒญ์—์„œ ํ™•์ธํ•˜์„ธ์š”!");
      document.getElementById("output3").textContent = "DevTools ํ™œ์šฉ: ์ฝ˜์†” ํ™•์ธ!";
    });

    /*****************************
    4๏ธโƒฃ XSS & CSRF ๋ฐฉ์–ด
    *****************************/
    document.getElementById("btnSecurity").addEventListener("click", function() {
      const userInput = "<script>alert('XSS ๊ณต๊ฒฉ!')</script>";
      
      // ๐Ÿ›‘ XSS ๋ฐฉ์ง€: ํŠน์ˆ˜๋ฌธ์ž๋ฅผ HTML ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜
      const sanitizedInput = userInput.replace(/</g, "&lt;").replace(/>/g, "&gt;"); 
      
      document.getElementById("output4").innerHTML = `์•ˆ์ „ํ•œ ์ถœ๋ ฅ: ${sanitizedInput}`;
    });
  </script>
</body>
</html>