javascript, циклические ссылки и утечки памяти

из того, что я помню о не слишком далеком прошлом, интерпретаторы Javascript страдали от проблем с утечкой памяти при столкновении с круговыми ссылками.

Это все еще так в последних браузерах? (например, Chrome, FF 3.5 и т. д.)

3 ответов


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

в IE6 это особенно пагубно тем, что вы не получаете память обратно, когда покидаете страницу; он ушел, пока вы не выйдете из браузера. В IE7 очистка страницы теперь возвращает память, но вы все равно можете столкнуться с трудностями, когда у вас есть длительное приложение. IE8 решает большую часть этого проблема правильно, превратив узлы DOM в собственные объекты JavaScript вместо объектов хоста. (Вы все равно можете вызвать утечки в IE8, включив другие неродные объекты, такие как объекты ActiveX, в цикл ссылок.)

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


добавить bobince ответ, я сделал несколько тестов с IE8.

Я пробовал почти все примеры, приведенные в http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

никто из них больше не пропускает память (по крайней мере, не воспринимаемым образом), за исключением примера, что удаляет дочерние узлы с прикрепленными к ним событиями.

этот пример, я думаю, что это лучше объясняется Дуглас Крокфорд в его queuetest2.

этот еще утечки памяти в IE8 и это довольно легко проверить, просто запустив тестовый скрипт и глядя на Диспетчер задач Windows-производительность-использование PF. Вы увидите, что использование PF увеличивается почти на 1 МБ за цикл (очень быстро).

но в IE8 память освобождается на странице unload (типа переход на новую страницу или перезагрузка этой же страницы) и, очевидно, также при полном закрытии браузера.

поэтому для того, чтобы конечный пользователь мог воспринимать эти утечки памяти на IE8 (как снижение производительности systerm), он должен оставаться на одной странице в течение длительного времени, что в настоящее время часто может происходить с AJAX, но эта страница также должна делать сотни childnodes удаление элементов с прикрепленным к ним событием.

тест Дугласа Крокфорда подчеркивает браузер с 10000 узлов добавлены, а затем удалены, это отлично подходит для показа вам проблемы, но в реальной жизни у меня никогда не было страницы, которая удалила бы более 10 элементов. INMHO обычно это быстрее использовать display: none вместо удаления всего набора узлов, вот почему я не использую removeChild что много.


для тех, кто может быть более заинтересован в утечке памяти IE8, объясненной выше, я сделал еще один тест, и кажется утечки mem вообще не отображаются в IE8 при использовании innerHTML на месте appendChild/removeChild добавление / удаление дочерних элементов с вложенными событиями. Так, очевидно, Дуглас Крокфорд функция Purge (предложенный им для предотвращения утечек памяти в IE) больше не нужен в IE8, по крайней мере, при использовании innerHTML...

(отредактировано благодаря комментарию 4esn0k ниже) ...более того, Дуглас Крокфорд!--24-->функция Purge не работает вообще на IE8, в его коде var a = d.attributes возвращает NO onclick атрибуты (или любой другой onevent атрибуты), которые были добавлены во время выполнения на IE8 (они возвращаются на IE7).

Дуглас Крокфорд говорит:

" функция продувки должна вызываться перед удалением любого элемента, либо методом removeChild или установка innerHTML собственность."

Я предоставляю здесь код для теста:

<body>    
   <p>queuetest2 similar to the one provided by Douglas Crockford
   at http://www.crockford.com/javascript/memory/leak.html
   <br>but this one adds/removes spans using innerHTML
   instead of appendChild/removeChild.</p>

   <div id="test"></div>    
   <script>
       /* ORIGINAL queuetest2 CODE FROM DOUGLAS CROCKFORD IS HERE
          http://www.crockford.com/javascript/memory/queuetest2.html */

      (function (limit, delay) 
      {
          var n = 0;
          var add = true;

          function makeSpan(n) 
          {
              var div = document.getElementById('test');
              //adding also an inline event to stress more the browser
              div.innerHTML = "<span onmouseover=\"this.style.color = '#00ff00';\">" + n + "</span>";
              var s = div.getElementsByTagName('span')[0];
              s.onclick = function(e) 
              {
                  s.style.backgroundColor = 'red';
                  alert(n);
              };
              return s;
          }

          function process(n) 
          {
              if(add)                    
                 s = makeSpan(n);
              else
                 s.parentNode.innerHTML = ""; //removing span by clearing the div innerHTML
              add = !add;
          }

          function loop() 
          {
              if (n < limit) 
              {
                  process(n);
                  n += 1;
                  setTimeout(loop, delay);
              }
          }

          loop();
      })(10000, 10);

   </script>
</body>

Что касается Internet Explorer 8-они говорят, что они исправили его в MS IE8:http://msdn.microsoft.com/en-us/library/dd361842 (VS.85).aspx

аналогичный поток здесь, в StackOverflow:знаете ли вы, что может вызвать утечку памяти в JavaScript?