Холст потребляет много памяти - PullRequest
5 голосов
/ 05 октября 2011

У меня проблемы с моей Canvas-реализацией, которую я открываю в оверлее.Элемент canvas имеет ширину 760px и высоту 2640px (я знаю, не спрашиваю).

Я рисую линии на каждом уровне 27.5px.

ctx.moveTo(0, y);
ctx.lineTo(760, y);
ctx.strokeStyle = 'rgb(100,100,100)';
ctx.stroke();

Кажется, что браузер выглядит так:подавиться этим при создании холста.В конце концов он проходит (1-5 сек) и память увеличивается на 20 МБ.

Закрытие оверлея не освобождает эту память.Когда я снова открываю оверлей (который перерисовывает холст), память снова увеличивается.И так далее, и так далее ... Мой процесс Chrome мгновенно переходит с 60 МБ памяти на 600+.

Изменение размера холста до высоты 264 пикселя и рисование линий на каждые 2,75 пикселя происходит намного быстрее и потребляеттолько около 4 МБ (что также, похоже, не очищается, конечно).

У кого есть несколько советов о том, как этого избежать.

Вот еще данные кода - это массив объектов, содержащий свойство Entries, которое также является массивом.

[ { Entries : [{...},{...},...] }, {...}, ... ]

var $canvas = container.find('canvas')
    , canvas = $canvas.get(0)
    , maxY = canvas.height
    , maxX = canvas.width
    , dX = maxX / (data.length + 1)
    , ctx = canvas.getContext('2d');


var x1, y1, y2, mh;

$.each(data, function (i, day) {
    if (!day.Entries) return;

     $.each(day.Entries, function (j, entry) {
         x1 = (i + 1) * dX;
         mh = entry.BeginDate.toHourMinutes();
         y1 = (((mh.h * 60) + mh.m) / 1440) * maxY;
         mh = entry.EndDate.toHourMinutes();
         y2 = (((mh.h * 60) + mh.m) / 1440) * maxY;

         switch (entry.Type) {
             case CALENDARTYPES.OPENINGHOUR:
                 ctx.beginPath();
                 ctx.rect(x1, y1, dX - 10, y2 - y1);
                 ctx.fillStyle = "rgb(125, 125, 125)";
                 ctx.fill();
                 ctx.closePath();
                 break;
             case CALENDARTYPES.BLOCKING:
                 ctx.clearRect(x1, y1, dX, y2 - y1);
                 break;
         };
      });
  });

       delete x1, y1, y2, mh;

       //Draw grid on canvas.

       var x = 0
           , y = +0.5
           , stepYH = maxY / 24
           , stepYQ = stepYH / 4
           , isHour = true;

       ctx.lineWidth = 1;

       while (y < maxY) {
           isHour = (((y - 0.5) % stepYH) == 0);
           ctx.moveTo(isHour ? x : x + dX, y);
           ctx.lineTo(maxX, y);
           ctx.strokeStyle = isHour ? 'rgb(175,175,175)' : 'rgb(100,100,100)';
           ctx.stroke();
           y += stepYQ;
       };

Ответы [ 2 ]

4 голосов
/ 06 октября 2011

Согласно комментариям:

Если вы не очищаете путь, вы в основном расширяете путь, и, поскольку .stroke() обводит (весь) путь, вы в конечном итоге будете рисовать все больше и больше по мере добавления новых точек с помощью .moveTo / .lineTo.

Возможно, имеет смысл использовать .beginPath(), чтобы вы только обводили новый путь, а не старый:

  • Путь очищается от памяти - меньше утечек
  • Старый путь не рисуется снова - меньше потери производительности
2 голосов
/ 05 октября 2011

Редактировать: Похоже, @pimvdb ударил ногтем по голове своим раствором. Пропуск вызовов начала и конца пути действительно продолжит строить бесконечный путь.


Можете ли вы опубликовать достаточно кода, чтобы мы могли просмотреть эту проблему?

Если в Chrome нет какой-то очень неясной ошибки, о которой я не знаю, использование холста с указанными вами размерами не является проблемой. Я работал над полноэкранными приложениями Canvas такого масштаба, и у меня не было проблем.

Увеличение памяти на 20 МБ кажется несколько чрезмерным, поэтому я склонен полагать, что вы создаете ненужные копии элемента canvas (или что-то связанное с ним) в памяти. Тот факт, что вы можете увеличить потребление памяти по требованию, закрыв и открыв оверлей, который отображает и повторно рисует холст, усиливает это убеждение.

Если вы сможете опубликовать свой код, я с радостью посмотрю его и помогу определить проблему.

...