$30 off During Our Annual Pro Sale. View Details »

JavaScript Essentials: Speicherverwaltung (German)

JavaScript Essentials: Speicherverwaltung (German)

Speicherverwaltung in Javascript. Gibt es hierzu eigentlich viel zu sagen? Im Gegensatz zu unseren C++-Kollegen, müssen wir das Speichermanagement in unserer Anwendung nicht selbst entwickeln. Denn das JavaScript-Speichermanagement ist automatisiert und läuft im Hintergrund. Trotzdem müssen wir zumindest die grundlegenden Prinzipien verstehen, damit unser Code keine Speicherlecks aufweist.

In diesem Vortrag werden die Grundlagen der Speicherverwaltung behandelt. Danach sehen wir uns die Möglichkeiten der Chrome DevTools und bevor wir uns mit den möglichen Problemfällen befassen, gibt es einen Ausflug in die prinzipielle Funktionsweise eines Garbage Collectors.

Rainer Hahnekamp

June 26, 2019
Tweet

More Decks by Rainer Hahnekamp

Other Decks in Technology

Transcript

  1. JavaScript Essentials: Speicherverwaltung enterJS 2019 26.6.2019 Rainer Hahnekamp (@rainerhahnekamp)

  2. Agenda Speicherverwaltung Allgemeine Theorie Analyse Probleme Memory Leaks Garbage Collector

  3. Warm-Up

  4. Teil I: Allgemeine Theorie Speicherverwaltung Allgemeine Theorie Analyse Probleme Memory

    Leaks Garbage Collector
  5. const product = { name: "Äpfel", category: "Früchte" };

  6. Betriebssystem Prozess JavaScript Engine JavaScript Quelltext const product = {

    name: "Äpfel", category: "Früchte" }; Virtueller Speicher Speicherhierarchie
  7. Betriebssystem Prozess JavaScript Engine JavaScript Quelltext const product = {

    name: "Äpfel", category: "Früchte" }; Virtueller Speicher Stack Heap Speicherhierarchie
  8. Betriebssystem Prozess JavaScript Engine JavaScript Quelltext const product = {

    name: "Äpfel", category: "Früchte" }; Virtueller Speicher Heap Stack Speicherhierarchie Garbage Collector
  9. Analyse Teil II: Analyse Speicherverwaltung Allgemeine Theorie Probleme Memory Leaks

    Garbage Collector
  10. Heap Größen von Websites Website HEAP Google Suche 7 Amazon.de

    21 Twitter 42 Facebook 43 Slack 62 Google Slides 108 GMail 115 Google Maps (3D) 144
  11. Teil III: Garbage Collector Speicherverwaltung Allgemeine Theorie Analyse Probleme Memory

    Leaks Garbage Collector
  12. Speicherallokation const doShopping = async () => { const basket

    = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ];total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; doShopping().then(console.log);
  13. Speicherallokation const doShopping = async () => { const basket

    = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") };n total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; doShopping().then(console.log);
  14. Speicherallokation const doShopping = async () => { const basket

    = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; doShopping().then(console.log);
  15. Speicherallokation const doShopping = async () => { const basket

    = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; };
  16. Speicherallokation const doShopping = async () => { const basket

    = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; Heap
  17. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; };
  18. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies
  19. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies total
  20. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); i=0 total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies total product (0)
  21. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); i=1 total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies total product (0) product (1)
  22. Speicherallokation Heap basket const doShopping = async () => {

    const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); i=2 total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies total product (0) product (1) Garbage Collection startet...
  23. Mark & Sweep Heap basket const doShopping = async ()

    => { const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 } ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); i=2 total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) { const currencies = { de: "€", gb: "£", cn: "¥" }; return currencies[country]; }; currencies total product (0) product (1) Garbage Collection starting...
  24. basket total product (1) product (0) Engine from-space to-space Mark

    & Sweep: Sweeping currencies
  25. basket total product (1) product (0) Engine from-space to-space Mark

    & Sweep: Sweeping currencies basket total
  26. product (1) product (0) Engine from-space to-space Mark & Sweep:

    Sweeping currencies basket total
  27. Infant Mortality Die meisten Objekten existieren nur eine kurze Zeit.

    Es wäre ineffizient, diese einzeln zu entfernen.
  28. Und es gibt noch mehr... const doShopping = async ()

    => { const basket = [ { product: "apple", amount: 3 }, { product: "water", amount: 1 }, { product: "milk", amount: 3 }, ··· ]; const total = { price: 0, currency: getCurrency("de") }; for (let i = 0; i < basket.length; i++) { const product = await fetchProduct(basket[i].product); total.price += product.price * basket[i].amount; } return total; }; const getCurrency = function(country) {··· }; mehrfache GCs noch mehr Produkte
  29. Generationen currencies basket product (0) product (1) total Engine basket

    total
  30. Generationen currencies basket product (0) product (1) total Engine basket

    total
  31. Generationen Engine product (2) product (3) 1. Generation: Nursery 2.

    Generation: Intermediate basket total
  32. Generationen Engine product (5) product (6) basket total New Generation

    Old Generation
  33. Reale Garbage Collectors • Variationen bzw. verbesserte Versionen: Das Prinzip

    ist jedoch dasselbe • Sehr viel Arbeit wird in schneller GC-Zyklen gesteckt. • Zusammenspiel mit der Rendering Engine des Browsers. • Anzahl der Objekte im Heap viel, viel höher.
  34. Teil IV: Probleme - Memory Leaks Speicherverwaltung Allgemeine Theorie Analyse

    Probleme Memory Leaks Garbage Collector
  35. Memory Leaks 1. Globaler Scope 2. DOM Nodes 3. Closures

  36. Globaler Scope 1/3 - kein var, let, const (function() {

    storage = new Array(1000000).fill("x"); })();
  37. Globaler Scope 2/3 - Typos (function() { let storage =

    ""; console.log("current length: " + storage.length); storge = new Array(1000000).fill("x"); })();
  38. Globaler Scope 3/3 - Falscher Context (function() { const person

    = { introduce: function() { console.log(this.introduction); }, setIntroduction: function(introduction) { this.introduction = introduction; } }; const getData = () => new Promise(resolve => resolve(new Array(1000000).fill("x"))); getData().then(person.setIntroduction); person.introduce(); })();
  39. Memory Leaks 1. Globaler Scope 2. DOM Nodes 3. Closures

  40. DOM Nodes - losgelöste Elemente const ul = document.createElement("ul"); run5Times("detached",

    () => { for (let i = 0; i < 1000; i++) { ul.appendChild(document.createElement("li")); } });
  41. DOM Nodes - losgelöste Elemente

  42. DOM Nodes - losgelöste Elemente

  43. Memory Leaks 1. Globaler Scope 2. DOM Nodes 3. Closures

  44. getPromotionFn getName printName data name async function getPromotionFn() { const

    data = await loadPromotion(); const getName = function() { return data[0]; }; const name = getName(); return function printName() { alert(`Kaufen Sie ${name}!!!`); }; } sollte im Speicher bleiben sollte entfernt werden (GC'ed)
  45. getPromotionFn Verschachtelte Funktionen teilen sich denselben Scope Scope getName printName

    data name data name async function getPromotionFn() { const data = await loadPromotion(); const getName = function() { return data[0]; }; const name = getName(); return function printName() { alert(`Kaufen Sie ${name}!!!`); }; }
  46. getPromotionFn Scope getName printName data name name async function getPromotionFn()

    { const data = await loadPromotion(); const getName = function() { return data[0]; }; const name = getName(); return function printName() { alert(`Kaufen Sie ${name}!!!`); }; }
  47. Eval ist evil

  48. Zusammenfassung • Heap als Haupt-Speicherstruktur in JavaScript • Google DevTools

    ermöglichen ◦ Heap Dumps (statisch Analyse) ◦ Verwendung des Heaps über Zeitraum zu messen (dynamische Analyse) • Garbage Collectoren verwenden sogenannte Roots um zu bestimmen, ob ein Objekt de-allokiert werden kann • Garbage Collections laufen als "Batch" • Closure können schwer auffindbare Memory Leaks verursachen
  49. Vielen Dank!!! Bitte um konstruktives Feedback!!! rainer.hahnekamp@gmail.com @rainerhahnekamp