Утечка URI данных в Safari (была: утечка памяти с помощью HTML5 canvas) - PullRequest
17 голосов
/ 16 декабря 2011

Я создал веб-страницу, которая получает растровые изображения в кодировке base64 через веб-сокет и затем рисует их на холсте.Работает отлично.Кроме того, использование памяти браузером (будь то Firefox, Chrome или Safari) увеличивается с каждым изображением и никогда не уменьшается.Итак, в моем коде должна быть утечка памяти или какая-то другая ошибка.Если я закомментирую вызов context.drawImage, утечка памяти не произойдет (но тогда, конечно, изображение никогда не рисуется).Ниже приведены фрагменты моей веб-страницы.Любая помощь приветствуется.Спасибо!

// global variables
var canvas;
var context;

...

ws.onmessage = function(evt)
{
    var received_msg = evt.data;
    var display_image = new Image();
    display_image.onload = function ()
    {
        context.drawImage(this, 0, 0);
    }
    display_image.src = 'data:image/bmp;base64,'+received_msg;
}

...

canvas=document.getElementById('ImageCanvas');
context=canvas.getContext('2d');

...

<canvas id="ImageCanvas" width="430" height="330"></canvas>

ОБНОВЛЕНИЕ 12/19/2011

Я могу обойти эту проблему, динамически создавая / уничтожая холст каждые 100 изображений или около того с помощью createElement / appendChild и removeChild.После этого у меня больше не возникает проблем с памятью в Firefox и Chrome.

Однако в Safari все еще есть проблема с использованием памяти, но я думаю, что это другая проблема, не связанная с Canvas.Кажется, есть проблема с многократным изменением «src» изображения в Safari, как будто оно никогда не освободит эту память.

display_image.src = 'data:image/bmp;base64,'+received_msg;  

Это та же проблема, описанная на следующем сайте: http://waldheinz.de/2010/06/webkit-leaks-data-uris/


ОБНОВЛЕНИЕ 12/21/2011

Я надеялся обойти эту проблему Safari путем преобразования полученной строки base64 в большой двоичный объект (с помощью функции «dataURItoBlob», которую я нашел)на этом сайте) и вернемся к URL с помощью window.URL.createObjectURL, установив src моего изображения на этот URL, а затем освободив память, вызвав window.URL.revokeObjectURL.Я получил все это работает, и Chrome и Firefox отображают изображения правильно.К сожалению, Safari не поддерживает BlobBuilder, поэтому я не могу использовать это решение.Это странно, поскольку во многих местах, включая книгу «Программирование приложений HTML5» О'Рейли, говорится, что BlobBuilder поддерживается в Safari / WebKit Nightly Builds.Я загрузил последнюю ночную сборку Windows с http://nightly.webkit.org/ и запустил WebKit.exe, но BlobBuilder и WebKitBlobBuilder по-прежнему не определены.


ОБНОВЛЕНИЕ 01/03/2012

Хорошо,Я наконец исправил это, расшифровав строку URI в кодировке base64 с помощью atob (), а затем создав массив данных пикселей и записав его на холст с помощью putImageData (см. http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/). Делая это таким образом (в отличие от постоянного изменения)."src" изображения и вызов drawImage в функции onload), я больше не вижу утечки памяти в Safari или любом браузере.

Ответы [ 4 ]

3 голосов
/ 16 декабря 2011

Без реального рабочего кода мы можем только догадываться, почему.

Если вы отправляете одно и то же изображение снова и снова, вы каждый раз создаете новое изображение.Это плохо.Вы хотели бы сделать что-то вроде этого:

var images = {}; // a map of all the images

ws.onmessage = function(evt)
{
    var received_msg = evt.data;
    var display_image;
    var src = 'data:image/bmp;base64,'+received_msg;
    // We've got two distinct scenarios here for images coming over the line:
    if (images[src] !== undefined) {
      // Image has come over before and therefore already been created,
      // so don't make a new one!
      display_image = images[src];
      display_image.onload = function () {
          context.drawImage(this, 0, 0);
      }
    } else {
      // Never before seen image, make a new Image()
      display_image = new Image();
      display_image.onload = function () {
          context.drawImage(this, 0, 0);
      }
      display_image.src = src;
      images[src] = display_image; // save it for reuse
    }
}

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

1 голос
/ 24 апреля 2012

Я не верю, что это ошибка. Кажется, проблема в том, что изображения накладываются друг на друга. Поэтому, чтобы очистить память, вам нужно использовать clearRect (), чтобы очистить ваш холст, прежде чем рисовать в нем новое изображение.

ctx.clearRect (0, 0, canvas.width, canvas.height);

Как очистить ваш холст имеет значение

0 голосов
/ 17 декабря 2011

Это очень интересно. Об этом стоит сообщить как об ошибке различным поставщикам браузеров (мне кажется, этого не должно быть). Вы можете получить ответы в духе «Не делай этого, вместо этого делай то-то и то-то», но, по крайней мере, тогда ты будешь знать правильный ответ и у тебя будет интересная вещь для записи в блоге (больше людей обязательно столкнутся с этот выпуск).

Следует попробовать сбросить src изображения (и обработчик загрузки) сразу после вызова drawImage. Возможно, он не освободит всю память, но может вернуть большую ее часть.

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

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

0 голосов
/ 16 декабря 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...