механизм сборки мусора javascript

внешний интерфейс JavaScript

---------------------Вот учебные заметки --------------------

Поскольку потребности клиентского бизнеса продолжают расти, мы будем занимать больше памяти, чем раньше. Но память не бесконечна, и что делать с теми переменными и объектами, которые нам уже не нужны? Это по одному вручную выпускать? На самом деле это не нужно,Javascript имеет механизм автоматической сборки мусора, который периодически освобождает память, занятую переменными и объектами, которые мы больше не используем

Механизм сборки мусора Javascript

Javascript найдет переменные, которые больше не используются, что означает конец жизненного цикла переменной. В Javascript есть два вида переменных - глобальные переменные и локальные переменные, цикл объявления всех переменных будет продолжаться до тех пор, пока страница не будет выгружена

Локальная переменная объявляется в функции, и цикл ее объявления начинается от выполнения функции до конца выполнения функции. В этом процессе локальным переменным будет выделено соответствующее пространство в куче или стеке для хранения их значений.Когда выполнение функции завершится, эти локальные переменные больше не будут использоваться, а место, которое они занимают, будет освобождено.

Но есть случай, когда локальные переменные не будут перерабатываться с окончанием функции, то есть локальные переменные используются переменными вне функции, одна из которыхЗакрытие, потому что после окончания выполнения функции переменные вне функции по-прежнему указывают на локальные переменные внутри функции, а локальные переменные в это время все еще используются, поэтому их нельзя переработать.

function func1 () {
      const obj = {}
}

function func2 () {
      const obj = {}
      return obj
}

const a = func1()
const b = func2()

В приведенном выше примереfunc1при выполнении какobjВыделяется блок памяти, но по мере завершения выполнения функцииobjЗанятое пространство также освобождается;func2При исполнении также дляobjвыделенной памяти, но из-заobjнаконец возвращается и назначаетсяbзаставить его все еще использоваться, поэтомуfunc2серединаobjЗанятая память не будет освобождена

Две реализации сборки мусора

Есть два способа реализовать сборку мусора, а именнопометить как очищенныйиподсчет ссылок

четко обозначенный

Когда переменная входит в среду выполнения, она помечается как «входящая в среду», а когда переменная покидает среду выполнения, она помечается как «выходящая из среды». Переменные, помеченные как «входящие в среду», не могут быть переработаны, поскольку они используются, и помеченные переменные, которые «выходят из среды», могут быть переработаны

function func3 () {
      const a = 1
      const b = 2
      // 函数执行时,a b 分别被标记 进入环境
}

func3() // 函数执行结束,a b 被标记 离开环境,被回收

подсчет ссылок

Подсчитайте, сколько раз ссылаются на переменные ссылочного типа после их объявления. Когда количество раз равно 0, переменная будет переработана.

function func4 () {
      const c = {} // 引用类型变量 c的引用计数为 0
      let d = c // c 被 d 引用 c的引用计数为 1
      let e = c // c 被 e 引用 c的引用计数为 2
      d = {} // d 不再引用c c的引用计数减为 1
      e = null // e 不再引用 c c的引用计数减为 0 将被回收
}

Однако у способа подсчета ссылок есть относительно очевидный недостаток — циклическая ссылка.

function func5 () {
      let f = {}
      let g = {}
      f.prop = g
      g.prop = f
      // 由于 f 和 g 互相引用,计数永远不可能为 0
}

В этом случае нужно вручную освободить память переменной

f.prop = null
g.prop = null

В современных браузерах Javascript используется так:четко обозначенный, поэтому нам не нужно беспокоиться о циклических ссылках

Что такое утечка памяти?

По сути, утечка памяти — это память, которая больше не нужна и по какой-то причине не может быть освобождена.

Распространенные случаи утечки памяти

1) Глобальные переменные выставляются как утечки памяти

             function fn() {
   		name = "你我贷"
             }
   	     console.log(name)


При работе с необъявленными переменными в JS в приведенном выше примере имя будет определено в глобальном объекте, который является окном в браузере.Глобальные переменные на странице будут уничтожены только при закрытии страницы.Таким образом, этот способ запись приведет к утечке памяти, конечно, в этом примере утечка только простой строки, но в реальном коде ситуация часто бывает хуже.

Еще один случай случайного создания глобальной переменной.

                function fn() {
   			this.name = "你我贷"
   		}
   		console.log(name)


В этом случае это указывает на окно глобальной переменной, и глобальная переменная создается случайно. Мы говорили о некоторых глобальных переменных, которые определяются неожиданно, а также о некоторых глобальных переменных, которые мы явно определяем в коде.Если вы используете эти глобальные переменные для временного хранения большого объема данных, не забудьте переназначить их в значение null после использования.

2) Неразрушенные таймеры и функции обратного вызова обнаруживаются как утечки памяти.

        function fn() {
    		return 2
    	}
    	var oTxt = fn();
   	setInterval(function() {
	    var oHtml = document.getElementById("test")
	    if(oHtml) {
	        oHtml.innerHTML = oTxt;
	    }
	}, 1000); // 每 1 秒调用一次

Если последующиеoHtml При удалении элемента весь таймер фактически не действует, но если не перезапускать таймер, то весь таймер по-прежнему действителен, не только таймер не может быть высвобожден памятью, но и зависимости в функции таймера не могут быть исправлено. В этом случаеfn Он также не может быть переработан.

3) Закрытие как утечка памяти

В разработке JS мы часто будем использовать замыкания, внутреннюю функцию, которая имеет доступ к переменным во внешней функции, которая ее содержит.В следующих случаях замыкания также могут вызывать утечку памяти.


3) Ссылка на DOM как утечку памяти

Много раз, когда мы работаем с Dom, мы сохраняем ссылку на Dom в массиве или на карте.

        var elements = {
    		txt: document.getElementById("test")
    	}
    	function fn() {
    		elements.txt.innerHTML = "1111"
    	}
    	function removeTxt() {
    		document.body.removeChild(document.getElementById('test'));
    	}
    	fn();
    	removeTxt()
    	console.log(elements.txt)


В приведенном выше случае, даже если мы удалим тестовый элемент, все еще будет ссылка на тестовый элемент, который все еще не может быть выровнен для освобождения памяти. Еще один момент, на который следует обратить внимание, — это ссылка на листовой узел дерева Dom.Например: если мы ссылаемся на элемент td в таблице, после удаления всей таблицы в Dom мы интуитивно чувствуем, что восстановление памяти должно быть восстановлено Другие элементы кроме ссылочного td. Но на самом деле этот элемент td является дочерним элементом всей таблицы и сохраняет ссылку на свой родительский элемент. Это не приведет к высвобождению памяти для всей таблицы. Поэтому мы будем осторожны со ссылками на элементы Dom .