путаница со сборкой мусора среди замыканий

Некоторое время я не был уверен в правилах сборки мусора JS вокруг замыкания, поэтому я полагаю, что мог бы также спросить... Вот хороший пример, который меня интересует, с использованием метода jQuery $.each:

storeSelection: function() {
    var enabledIds = {};

    $.each(this.nodes, function(index, node) {
        if (node.enabled) {
            enabledIds[ node.id ] = true;
        }
    });

    this.selection = enabledIds;
}

Приведенный выше фрагмент, конечно же, является частью литерала объекта. Итак, я создал новый объект в верхней части внешней функции, который будет хранить идентификаторы включенных элементов в массиве. Используя метод jQuery .each(), я перебираю массив элементов и регистрирую включенные идентификаторы. Наконец, я сохраняю выбор как элемент родительского объекта.

Мой вопрос касается той внутренней функции, которая ссылается на объект enabledIds из внешней области. Поскольку enabledIds останется, не помешает ли это сбору внутренней функции? Я бы предположил, что нет, потому что это просто переменная, которая очищается в конце внутренней функции, верно? Чтобы стать утечкой, я предполагаю, что внутренняя функция должна будет сделать жесткую ссылку на внешний объект, например:

$.each(this.nodes, function(index, node) {
    this.badIdea = enabledIds;
    if (node.enabled) {
        enabledIds[ node.id ] = true;
    }
});

Однако... Я всегда туманно отношусь к этому правилу. Будем признательны за любую помощь в устранении этой путаницы!


person bigmac    schedule 22.05.2012    source источник


Ответы (2)


Нет, даже вашего второго примера недостаточно, чтобы вызвать утечку. badIdea прикрепляется к отдельным узлам, а блок $.each завершает работу и удаляется сборщиком мусора. Все современные браузеры используют алгоритм «пометки и очистки» для сборки мусора javascript, который следует ассоциациям от родительского к дочернему и собирает любые «недостижимые объекты», то есть все, к чему не может получить доступ одно из этих деревьев.

person Chris Pratt    schedule 22.05.2012

Вы правы, переменные из внутренней функции (index, node) будут удалены сборщиком мусора, потому что к ним больше нельзя получить доступ.

В этом примере вы можете получить доступ к bigstr?

a = function() {
        var bigstr = new Array(1000000).join('x');
        return function() { return bigstr; };
    }();

Да, можно: a(), так не собирается. Как насчет этого примера:

a = function() {
        var bigstr = new Array(1000000).join('x');
        return function(n) { return eval(n); };
    }();

Опять же, вы можете: a('bigstr').

Но как насчет этого:

a = function() {
        var smallstr = 'x';
        var bigstr = new Array(1000000).join('x');
        return function(n) { return smallstr; };
    }();

Вы больше не можете получить к нему доступ, и это кандидат на сборку мусора.

person Alexey Lebedev    schedule 22.05.2012