Пользователь
0,0
рейтинг
29 июня 2012 в 17:53

Разработка → Утечки памяти в замыканиях JavaScript перевод

Цитата из Google JavaScript style guide:

Возможность создавать замыкания — похоже, самая полезная и часто остающаяся без внимания особенность JS.

Однако, одну вещь нужно иметь виду: замыкание хранит указатель на замыкаемый им контекст. В результате, прикрепление замыкания к элементу DOM может породить циклическую зависимость и, следовательно, утечку памяти. Например, в следующем куске кода:

function foo(element, a, b) {
  element.onclick = function() { /* использует a и b */ };
}


замыкание хранит указатель на element, a и b даже в том случае, если оно никогда element не использует. А раз element тоже хранит указатель на замыкание, то получается цикл, который никогда не будет вычищен сборщиком мусора.

В подобных случаях код нужно структурировать следующим образом:

function foo(element, a, b) {
  element.onclick = bar(a, b);
}

function bar(a, b) {
  return function() { /* использует a и b */ }
}


Похоже, на текущий момент это наиболее часто встречающийся на практике пример утечки памяти в JavaScript.
Перевод: Rich Atkinson
Максим Казанцев @mkaz
карма
26,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (31)

  • –6
    спасибо, кеп(это я автору, а не переводчику).

    Вопрос в том как научить программистов тому что javascript это не jQuery, как сказать что это достаточно интересный и своеобразный язык и в нём надо разораться а не применять вслепую.
    • –8
      Я с вам согласен, но к сожалению JavaScript приобрел такую популярность только после jQuery (или подобных), наверное. Еще 3 года назад многие с опасной рассматривали вариант внедрения js — так как не кроссбраузерно и т.д.
      • +4
        Я боюсь после jQuery javascript не получил популярности. Равно как после RoR не стала сильно популярнее первая R.
      • +11
        приобрел популярность? js не кроссбраузерно? есть альтернативы? опасность внедрения js? я в параллельной вселенной? o_O
        • –5
          аватар смените, косяки разметки напрягают на подсознательном уровне
          • +2
            как часто вы собираетесь пялиться на мой аватар?
            • 0
              До вашего аватара мне нет дела, просто использовать в качестве его такую картинку — не очень правильно. Если вы так не считаете, ваше право. Я просто указал на ошибку.
        • 0
          да js ну просто очень опасен
          (function(){arguments.callee();})();
          

          А если серьезно, то привыкая к (а часто начиная с) jQuery, программисты забывают о всей красоте, изящности и возможностях javascript.

          >>Вопрос в том как научить программистов тому что javascript это не jQuery, как сказать что это достаточно интересный и своеобразный язык и в нём надо разораться а не применять вслепую.

          Тут скорее надо заинтересовать, люди часто ленятся взять хорошую книгу по языку и прочитать от корки до корки, гораздо проще ведь нагуглить что-то вроде «увеличение картинки плагин jQuery».
          • 0
            >> привыкая к (а часто начиная с) jQuery, программисты забывают о всей красоте, изящности и возможностях javascript.

            С чего вы взяли что забывают, скорее вообще не знали :)
          • 0
            А по-моему все вокруг зазря сгущают краски вокруг JQuery. Я начал изучение JS именно с JQ. И лишь спустя время мне стало интересно, а что же у этого JQ внутри, раз он из такого жуткого (как мне тогда казалось) JS делает такую конфетку.
            Начинать надо с простого. А JQ это просто и наглядно.
      • +1
        Вы не ошиблись ноликом? Я Уже 6 лет на JS пишу и альтернативы до сих пор никакой нет.
    • +3
      Учатся, как практика показывает, на ошибках. А ошибки обычно возникают с первым более-менее содержательным асинхронным вызовом.
    • +6
      Пост написан автором больше года назад, и там же, в комментах ему на пальцах объяснили, что это уже неактуально.
      • +6
        Этому переводу не хватает перевода комментариев из оригинала :)
    • 0
      В jQuery, кстати, тоже возможны утечки, если, например, будет смешанное использование jQuery и стандартных вызовов (из-за использования jQuery.cache).
    • НЛО прилетело и опубликовало эту надпись здесь
      • +2
        Ну, утечки памяти — это тоже не совсем язык, а особенности конкретной реализации. И DOM-вызовы — API браузера, то есть тоже своего рода библиотека.
        • НЛО прилетело и опубликовало эту надпись здесь
  • +6
    Это что же за сборщик мусора такой, который не умеет с циклическими зависимостями справляться? А что делать, если нужно использовать в обработчике element, а не только a и b?
    • –4
      В php со сборкой мусора с циклическими зависимостями тоже бывает беда.
    • 0
      Тут немного коряво, вообще говоря в as3 который тоже EcmaScript 262 циклические ссылки удаляются, но вот если хоть один элемент изх цикла висит на экране весь цикл и повиснет на одном элементе. Это очень частая причина утечек.
      • +2
        Если мне не изменяет память, в ECMAScript вообще не определен алгоритм работы сборщика мусора, потому все зависит от конечной реализации.

        А что касается IE, то до восьмой версии сборщик хоть и работал по принципу mark&sweep, а значит, был способен чистить циклические ссылки, но из-за особенностей работы COM (в котором используется подсчет ссылок) наличие ссылок в expando DOM-элемента на объекты скриптового движка в одном замыкании с объектами, ссылающимися на этот DOM-элемент приводило к таким неразрешимым случаям.
    • 0
      Насколько я помню, несвежие IE этим точно страдали
  • НЛО прилетело и опубликовало эту надпись здесь
    • –4
      JS отжирает памяти на большинстве приложений очень нехило, а если учесть что страница может быть открыта продолжительное время, то такого рода статьи грех называть бредом!
  • +16
    Фигня. И хром, и фф, и опера, и эксплорер версий 8+ нормально с такими утечками справляются.
    Ну и для того, чтоб избавиться от них, не надо выносить обработчик наружу, можно в замыкании ссылку на элемент прибить:
    function foo(element, a, b) {
      element.onclick = function() { /* использует a и b */ };
      element = null;
    }
    
  • +1
    Это актуально только в части браузеров, а точнее — в старых FF и IE.

    Такая утечка возникает только тогда, когда GC использует «счетчик ссылок» (в FF счетчик ссылок использовался для элементов DOM) и из-за этого не может разрешить циклические ссылки.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    бред
  • 0
    Браузеры ведут себя по-разному в таких ситуациях, если открыть такой код через web inspector в хроме, то можно увидеть, что замыкание может и не сохранять те элементы, которые оно не использует, т.е. если внутри onclick колбэка не будет обращения к element, то замыкание не сохранит ссылку на него в разделе Scope variables это можно увидеть

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.