@Ivanushka255

В этом случае объект очищается по причине работы алгоритма Mark-and-sweep или это просто эффект работы локальной переменной...?

В этом случае объект очищается по причине работы алгоритма Mark-and-sweep или это просто эффект работы локальной переменной, в которую он был помещен?

Я не понимаю о чем конкретно идет здесь речь:
Теперь циклические ссылки - не проблема
В вышеприведённом первом примере после возврата из функции оба объекта не имеют на себя никаких ссылок, доступных из глобального объекта. Соответственно, сборщик мусора пометит их как недоступные и затем удалит.


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


Переменная а недоступна после прекращения работы функции.
  • Вопрос задан
  • 62 просмотра
Пригласить эксперта
Ответы на вопрос 1
bingo347
@bingo347 Куратор тега JavaScript
Crazy on performance...
Все сильно зависит от движка, но в основном принципы похожи. Расскажу на примере v8 (chrome, node).
Первое, что надо понять, в v8 сборка мусора основана на поколениях. И в разных поколениях применяются разные алгоритмы. В v8 используется 3 поколения:
- Молодое (собирается по наполнению (часто), но быстрым упрощенным алгоритмом)
- Старое (собирается по расписанию (редко), здесь как раз Mark & Sweep)
- Особое (я не очень про него знаю, здесь очень большие объекты + объекты с прямым доступом из глобального)

Второе, что нужно понять, все данные доступные из JS v8 хранит на куче, независимо примитив это или js-объект. С точки зрения GC все есть объект, и числа и строки и функции.

Теперь более подробно про молодое поколение. Его цель - быть быстрым, быстро выделять и освобождать память. Создатели v8 прекрасно знают, что аллокация на куче - крайне затратная операция, поэтому здесь преаллоцированы 2 страницы памяти, которые используются по очереди. Заодно можно получить бонус в работе с процессорным кэшем, за счет того, что здесь "горячие" данные и они лежат рядом, а значит попадут на одну кэш линию. Когда мы создаем новый объект, v8 просто помещает его в конец активной страницы. Если места не хватает происходит быстрая сборка мусора. А еще здесь используется подсчет ссылок (он быстрее), но только для ссылок из старого поколения - если есть хоть 1 такая ссылка - объект живой, а так же живо все его объектное дерево. Так же нельзя "убивать" объект, если на него есть ссылки из стэка. Все остальное "мертвое". Живые объекты переносятся в начало второй страницы памяти (заодно происходит дефрагментация памяти), после чего она становится активной. Если объект пережил 3 таких быстрых сборки, то вместо второй страницы его переносят на старое поколение, при этом происходит аллокация памяти.

В Вашем примере задействовано только молодое поколение.
function f() {
    // это мертвый код, после оптимизации f строка вообще не будет память использовать
    let a = 'some text';

    // это 2 молодых объекта, на них уже ссылается контекст вызова f, а на него ссылается стэк
    var obj1 = {};
    var obj2 = {};
    obj1.p = obj2; // obj1 references obj2
    obj2.p = obj1; // obj2 references obj1. This creates a cycle.

    // при завершении функции стэк перестает ссылаться на контекст вызова
    // контекст вызова умрет при ближайшей GC,
    // а вместе с ним и obj1 и obj2, так как их никто не отметит "живыми"
}
f();
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы