aboutsummaryrefslogtreecommitdiff
path: root/files/uk/web/javascript/memory_management/index.html
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:43:23 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:43:23 -0500
commit218934fa2ed1c702a6d3923d2aa2cc6b43c48684 (patch)
treea9ef8ac1e1b8fe4207b6d64d3841bfb8990b6fd0 /files/uk/web/javascript/memory_management/index.html
parent074785cea106179cb3305637055ab0a009ca74f2 (diff)
downloadtranslated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.gz
translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.tar.bz2
translated-content-218934fa2ed1c702a6d3923d2aa2cc6b43c48684.zip
initial commit
Diffstat (limited to 'files/uk/web/javascript/memory_management/index.html')
-rw-r--r--files/uk/web/javascript/memory_management/index.html204
1 files changed, 204 insertions, 0 deletions
diff --git a/files/uk/web/javascript/memory_management/index.html b/files/uk/web/javascript/memory_management/index.html
new file mode 100644
index 0000000000..0022a81129
--- /dev/null
+++ b/files/uk/web/javascript/memory_management/index.html
@@ -0,0 +1,204 @@
+---
+title: Керування пам'яттю
+slug: Web/JavaScript/Memory_Management
+tags:
+ - JavaScript
+ - Збирання сміття
+ - пам'ять
+ - продуктивність
+translation_of: Web/JavaScript/Memory_Management
+---
+<div>{{JsSidebar("Advanced")}}</div>
+
+<p>У низькорівневих мовах, наприклад C, існують примітивні функції для ручного керування пам'яттю, такі як <a href="https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html">malloc()</a> та <a href="https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions">free()</a>. В той же час JavaScript автоматично виділяє пам'ять при створенні об'єктів та звільняє її, коли вони більше не використовуються (<em>збирання сміття</em>). Ця автоматичність є потенційним джерелом плутанини: вона може дати розробникам хибне враження, що їм не потрібно хвилюватись щодо керування пам'яттю.</p>
+
+<h2 id="Життєвий_цикл_памяті">Життєвий цикл пам'яті</h2>
+
+<p>Незалежно від мови програмування, життєвий цикл пам'яті завжди приблизно той самий:</p>
+
+<ol>
+ <li>Виділення потрібної пам'яті</li>
+ <li>Використання виділеної пам'яті (читання, запис)</li>
+ <li>Вивільнення виділеної пам'яті, коли вона більше не потрібна</li>
+</ol>
+
+<p>Друга частина в усіх мовах є явною. Перша та остання частини є явними у низькорівневих мовах, але, як правило, неявні у мовах високого рівня, таких як JavaScript.</p>
+
+<h3 id="Виділення_памяті_у_JavaScript">Виділення пам'яті у JavaScript</h3>
+
+<h4 id="Ініціалізація_значень">Ініціалізація значень</h4>
+
+<p>Щоб не турбувати розробника виділеннями пам'яті, JavaScript автоматично виділяє пам'ять, коли оголошуються початкові значення.</p>
+
+<pre class="brush: js">var n = 123; // виділяє пам'ять для числа
+var s = 'блабла'; // виділяє пам'ять для рядка
+
+var o = {
+ a: 1,
+ b: null
+}; // виділяє пам'ять для об'єкта та значень, що він містить
+
+// (як з об'єктом) виділяє пам'ять для масиву та
+// значень, що він містить
+var a = [1, null, 'аовл'];
+
+function f(a) {
+ return a + 2;
+} // виділяє пам'ять для функції (об'єкт, який можна викликати)
+
+// функціональні вирази також виділяють пам'ять для об'єкта
+someElement.addEventListener('click', function() {
+ someElement.style.backgroundColor = 'blue';
+}, false);
+</pre>
+
+<h4 id="Виділення_памяті_через_виклики_функцій">Виділення пам'яті через виклики функцій</h4>
+
+<p>Виклики деяких функцій виділяють пам'ять під об'єкт.</p>
+
+<pre class="brush: js">var d = new Date(); // виділяє пам'ять під об'єкт Date
+
+var e = document.createElement('div'); // видділяє пам'ять під елемент DOM</pre>
+
+<p>Деякі методи виділяють пам'ять для нових значень чи об'єктів:</p>
+
+<pre class="brush: js">var s = 'йцуке';
+var s2 = s.substr(0, 3); // s2 - новий рядок
+// Оскільки рядки є незмінними,
+// JavaScript може вирішити не виділяти пам'ять,
+// а лише зберегти діапазон [0, 3].
+
+var a = ['ouais ouais', 'nan nan'];
+var a2 = ['generation', 'nan nan'];
+var a3 = a.concat(a2);
+// новий масив з 4 елементів, що є
+// поєданням елементів a та a2.
+</pre>
+
+<h3 id="Використання_значень">Використання значень</h3>
+
+<p>Використання значень, по суті, означає читання та запис у виділеній пам'яті. Це можна зробити зчитуванням та записом значення змінної чи властивості об'єкта, чи навіть передачею аргументу у функцію.</p>
+
+<h3 id="Звільнення_памяті_коли_вона_більше_не_потрібна">Звільнення пам'яті, коли вона більше не потрібна</h3>
+
+<p>Більшість проблем керування пам'яттю виникають на цій стадії. Найскладніший аспект цього етапу полягає у визначенні, коли виділена пам'ять більше не потрібна. </p>
+
+<p>Низькорівневі мови вимагають, щоб розробник вручну визначав, у якій точці програми виділена пам'ять більше не потрібна, та звільняв її.</p>
+
+<p>Деякі високорівневі мови, такі як JavaScript, використовують форму автоматичного керування пам'яттю, відому як <a href="https://uk.wikipedia.org/wiki/%D0%97%D0%B1%D0%B8%D1%80%D0%B0%D0%BD%D0%BD%D1%8F_%D1%81%D0%BC%D1%96%D1%82%D1%82%D1%8F">збирання сміття</a> (ЗС). Збирач сміття відслідковує виділення пам'яті та визначає момент, коли блок виділеної пам'яті більше не потрібний, і повертає його. Цей автоматичний процес є неточним, оскільки загальна проблема визначення, чи потрібна наразі та чи інша ділянка пам'яті, є <a href="https://uk.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%96%D1%87%D0%BD%D0%B0_%D1%80%D0%BE%D0%B7%D0%B2%27%D1%8F%D0%B7%D0%BD%D1%96%D1%81%D1%82%D1%8C">нерозв'язною</a>.</p>
+
+<h2 id="Збирання_сміття">Збирання сміття</h2>
+
+<p>Як було зазначено вище, загальна проблема автоматичного визначення того, що якась ділянка пам'яті "більше не потрібна", є нерозв'язною. Як наслідок, збирачі сміття впроваджують обмеження вирішення загальної проблеми. Цей розділ пояснює концепції,  необхідні для розуміння головних алгоритмів збирання сміття та відповідних обмежень.</p>
+
+<h3 id="Посилання">Посилання</h3>
+
+<p>Головна концепція, на яку покладаються алгоритми збирачів сміття - це концепція <em>посилань</em>. У контексті керування пам'яттю об'єкт посилається на інший об'єкт, якщо звертається до нього (явно чи неявно). Наприклад, об'єкт JavaScript має посилання на свій <a href="/uk/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">прототип</a> (неявне посилання) та на значення своїх властивостей (явне посилання).</p>
+
+<p>У цьому контексті поняття "об'єкта" є ширшим, ніж звичайні об'єкти JavaScript, і містить також області видимості функцій (або глобальну область видимості).</p>
+
+<h3 id="Збирання_сміття_через_підрахунок_посилань">Збирання сміття через підрахунок посилань</h3>
+
+<p>Це найпримітивніший алгоритм збирання сміття. Цей алгоритм звужує проблему з визначення того, чи об'єкт досі є потрібним, до визначення того, чи мають інші об'єкти досі посилання на даний об'єкт. Об'єкт називається "сміттям", або підлягає збиранню, якщо на нього вказує нуль посилань.</p>
+
+<h4 id="Приклад">Приклад</h4>
+
+<pre class="brush: js">var x = {
+ a: {
+ b: 2
+ }
+};
+// Створено 2 об'єкта. Один має посилання у іншому як одна з його властивостей.
+// Інший має посилання через присвоєння його змінній 'x'.
+// Зрозуміло, що жоден з них не може бути прибраний.
+
+
+var y = x; // Змінна 'y' - друга сутність, що має посилання на об'єкт.
+
+x = 1; // Тепер об'єкт, що початково був присвоєний 'x', має унікальне посилання,
+ // втілене у змінній 'y'.
+
+var z = y.a; // Посилання на властивість 'a' об'єкта.
+ // Цей об'єкт тепер має 2 посилання: одне у вигляді властивості,
+ // інше у вигляді змінної 'z'.
+
+y = 'mozilla'; // Об'єкт, що початково був присвоєний 'x', тепер має нуль посилань.
+ // Він може бути прибраний.
+ // Однак, на його властивість 'a' досі посилається
+ // змінна 'z', тому її не можна вивільнити.
+
+z = null; // Властивість 'a' об'єкта, що початково був присвоєний x,
+ // має нуль посилань. Об'єкт тепер може бути прибраний.
+</pre>
+
+<h4 id="Обмеження_Циклічні_посилання">Обмеження: Циклічні посилання</h4>
+
+<p>Існує обмеження у випадку циклічних посилань. У наступному прикладі два об'єкти створені з властивостями, в яких вони посилаются один на одного, таким чином створюючи цикл. Вони вийдуть за межі області видимості, коли завершиться виклик функції. В цей момент вони стають непотрібними, і їхня виділена пам'ять має бути повернена. Однак, алгоритм, що підраховує посилання, не вважатиме їх готовими для повернення, оскільки кожен з двох об'єктів має принаймні одне посилання, що вказує на нього, в результаті жоден з них не позначається для збирання сміття. Циклічні посилання є типовою причиною витоків пам'яті.</p>
+
+<pre class="brush: js">function f() {
+ var x = {};
+ var y = {};
+ x.a = y; // x посилається на y
+ y.a = x; // y посилається на x
+
+ return 'йцуке';
+}
+
+f();
+</pre>
+
+<h4 id="Приклад_з_реального_життя">Приклад з реального життя</h4>
+
+<p>Internet Explorer 6 та 7 відомі тим, що їхні збирачі сміття для об'єктів DOM працюють на основі підрахунку посилань. Цикли є типовою помилкою, що призводить до витоків пам'яті:</p>
+
+<pre class="brush: js">var div;
+window.onload = function() {
+ div = document.getElementById('myDivElement');
+ div.circularReference = div;
+ div.lotsOfData = new Array(10000).join('*');
+};
+</pre>
+
+<p>У наведеному прикладі DOM-елемент "myDivElement" має циклічне посилання на самого себе у властивості "circularReference". Якщо ця властивість не буде явно видалена чи обнулена, збирач сміття, що підраховує посилання, завжди матиме принаймні одне наявне посилання і триматиме DOM-елемент у пам'яті, навіть якщо він був видалений з DOM-дерева. Якщо DOM-елемент містить великий об'єм даних (проілюстровано у наведеному прикладі властивістю "lotsOfData"), пам'ять, зайнята цими даними, ніколи не буде вивільнена, що може призвести до проблем, пов'язаних з пам'яттю, наприклад, переглядач ставатиме все повільнішим.</p>
+
+<h3 id="Алгоритм_маркування_та_прибирання_mark-and-sweep">Алгоритм маркування та прибирання (mark-and-sweep)</h3>
+
+<p>Цей алгоритм звужує визначення "об'єкта, який більше не потрібен" до "недосяжного об'єкта".</p>
+
+<p>Даний алгоритм використовує набір об'єктів, що називаються <em>коренями. </em>У JavaScript корінь є глобальним об'єктом. Періодично збирач сміття починатиме від цих коренів, знаходитиме усі об'єкти, що мають посилання у коренях, далі усі об'єкти, що мають посилання у них, і т. д. Таким чином, починаючи від коренів, збирач сміття знайде усі <em>досяжні</em> об'єкти та збере усі недосяжні об'єкти.</p>
+
+<p>Цей алгоритм є покращенням попереднього, оскільки об'єкт, що має нуль посилань, є об'єктивно недосяжним. Протилежне не є істиною, як ми бачили на прикладі циклічних посилань.</p>
+
+<p>Станом на 2012 рік усі сучасні переглядачі використовують збирачі сміття з алгоритмом маркування та прибирання. Усі покращення в галузі збирання сміття у JavaScript (генераційне/інкрементне/конкурентне/паралельне збирання сміття) за останні кілька років є покращеннями реалізації даного алгоритму, а не покращеннями самого алгоритму збирання сміття чи скороченням його визначення моменту, коли "об'єкт більше не потрібен".</p>
+
+<h4 id="Циклічні_посилання_більше_не_є_проблемою">Циклічні посилання більше не є проблемою</h4>
+
+<p>У наведеному вище прикладі, коли завершується виклик функції, два об'єкти більше не мають посилань з жодного ресурсу, досяжного з глобального об'єкта. Як наслідок, збирач сміття визнає їх недосяжними та поверне виділену під них пам'ять.</p>
+
+<h4 id="Обмеження_Ручне_вивільнення_памяті">Обмеження: Ручне вивільнення пам'яті</h4>
+
+<p>Бувають випадки, коли було б зручно власноруч визначити, коли й яка пам'ять буде звільнена. Щоб звільнити пам'ять об'єкта, його треба зробити явно недосяжним.</p>
+
+<p>Станом на 2019 рік немає можливості явно чи програмно запустити збирання сміття у JavaScript.</p>
+
+<h2 id="Node.js">Node.js</h2>
+
+<p>Node.js пропонує додаткові можливості та інструменти для конфігурування та відлагодження проблем з пам'яттю, які можуть бути недоступні для JavaScript, що виконується у середовищі переглядача.</p>
+
+<h4 id="Прапори_рушія_V8">Прапори рушія V8</h4>
+
+<p>Максимальний розмір доступної пам'яті купи може бути збільшений за допомогою прапору:</p>
+
+<p><code>node --<em>max-old-space-size=6000</em> index.js</code></p>
+
+<p>Ми також можемо викликати збирач сміття для відлагодження проблем з пам'яттю, використовуючи прапор та <a href="https://nodejs.org/uk/docs/guides/debugging-getting-started/">Chrome Debugger</a>:</p>
+
+<pre class="brush: bash">node --expose-gc --inspect index.js</pre>
+
+<h4 id="Див._також">Див. також</h4>
+
+<ul>
+ <li><a class="external" href="http://www.ibm.com/developerworks/web/library/wa-memleak/">Стаття IBM про "Шаблони витоків пам'яті у JavaScript" (2007)</a></li>
+ <li><a class="external" href="http://msdn.microsoft.com/en-us/magazine/ff728624.aspx">Стаття Kangax про те, як зареєструвати обробник подій та запобігти витокам пам'яті (2010)</a></li>
+ <li><a href="/uk/docs/Mozilla/Performance" title="https://developer.mozilla.org/en-US/docs/Mozilla/Performance">Продуктивність</a></li>
+</ul>