画布消耗大量内存

发布于 2024-12-08 09:43:13 字数 2175 浏览 0 评论 0原文

我在使用覆盖层打开的 Canvas 实现时遇到困难。 canvas 元素宽 760px,高 2640px(我知道,别问)。

我每隔 27.5 像素高画一条线。

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

显然,浏览器在创建画布时似乎对此“感到窒息”。最终它完成了(1-5秒)并且内存增加了20MB。

关闭覆盖似乎并没有释放该内存。 当我重新打开覆盖层(重新绘制画布)时,内存再次增加。 等等,等等…… 我的 chrome 进程很快就从 60MB 内存增加到了 600+。

将画布大小调整为 264 像素高并每 2.75 像素绘制线条速度更快,并且仅消耗约 4MB(当然这似乎也没有被清除)。

谁有一些关于如何避免这种情况的指示。


Here is more code data is an array of objects containing an Entries property which is also an array.

[ { 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;
       };

I am having difficulties with my Canvas-implementation which I open in an overlay.
The canvas element is 760px wide and 2640px high (I know, don't ask).

I am drawing lines at every 27.5px high.

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

Appearantly the browser seems to 'choke' on this when creating the canvas. Eventually it comes through (1-5secs) and memory is raised by 20MB.

Closing the overlay does not seem to free this memory.
When I reopen the overlay (which redraws the canvas), the memory is again increased.
And so on, and so on...
My chrome process goes from 60MB memory to 600+ in no time this way.

Resizing the canvas to 264px high and drawing lines at every 2.75px goes way faster and consumes only about 4MB (which also does not seem to be cleared of course).

Who has some pointers on how to avoid this.


Here is more code
data is an array of objects containing an Entries property which is also an array.

[ { 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;
       };

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

爺獨霸怡葒院 2024-12-15 09:43:13

根据评论:

如果您不清除路径,则基本上是在扩展路径,并且由于 .lines() 描边了(整个)路径,因此您最终会绘制越来越多的内容当您使用 .moveTo/.lineTo 添加更多点时。

使用 .beginPath() 可能更有意义,这样您只绘制新路径,而不绘制旧路径:

  • 路径从内存中清除 - 更少泄漏
  • 旧路径不再绘制 - 更少性能损失

As per the comments:

If you do not clear the path, you're basically extending the path, and since .stroke() strokes the (entire) path, you'll end up drawing more and more as you add more points using .moveTo/.lineTo.

It might make more sense to use .beginPath() so that you only stroke the new path and not the old path as well:

  • Path is cleared from memory - less leaks
  • Old path is not drawn again - less performance loss
云之铃。 2024-12-15 09:43:13

编辑: 看起来@pimvdb 的解决方案一语中的。省略开始和结束路径调用确实会继续构建一条永无止境的路径。


您能否发布足够的代码以便我们查看此问题?

除非 Chrome 中有一些我不知道的非常隐蔽的错误,否则使用具有您指定尺寸的画布不是问题。我曾经开发过这种规模的全屏画布应用程序,但没有遇到任何问题。

内存增加 20MB 确实看起来有些过多,所以我倾向于相信您在内存中不必要地创建 canvas 元素(或与之相关的东西)的副本。事实上,您可以通过关闭和打开显示和重新绘制画布的覆盖层来按需增加内存消耗,这一事实强化了这一信念。

如果您可以发布您的代码,我很乐意查看它并帮助您找出问题。

Edit: It looks like @pimvdb hit the nail on the head with his solution. Omitting the begin and end path calls will indeed continue to build a never-ending path.


Can you post enough of your code to allow us to view this issue?

Unless there's some very obscure bug in Chrome that I'm not aware of, using a canvas with the dimensions you specified is not an issue. I've worked on full-screen canvas applications of that magnitude and haven't had any issues.

The memory increasing by 20MB does seem somewhat excessive, so I would be inclined to believe that you are unnecessarily creating copies of the canvas element (or something related to it) in memory. The fact that you can increase the memory consumption on demand by closing and opening the overlay that displays and re-draws the canvas reinforces this belief.

If you can post your code, I'd be happy to take a look at it and help you identify the problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文