【问题标题】:HTML5 Canvas memory leak performance issueHTML5 Canvas 内存泄漏性能问题
【发布时间】:2015-10-05 19:34:45
【问题描述】:

我有 2 个canvas 元素,我以 125 毫秒的间隔绘制它们。

由于它们的工作性质,它们都必须完全重新绘制,因此不可能只重新绘制它们的某些部分来提高性能。

问题

当我在任务管理器中看到时,工作集(内存)会根据我重新绘制画布的速度不断增加。

到目前为止我已经尝试过什么

  1. 使用 clearRect 进行清理(而不是再次设置它的宽度)

  2. 尝试删除画布的父 div 并重新创建 div 并在其中再次加载画布:这有助于减缓内存增加,但并不能完全阻止它。

  3. 将不同的 context.fills 减少到尽可能少,但同样由于画布的性质,它仍然有很多这样的内容。

即使我做了所有这些事情,Working Set 也可能很高,但不应不断增加。

对如何控制内存泄漏有什么建议吗?


更新: 泄漏不在画布图纸中。我正在使用网络工作者将数据传递到画布,该画布在某处泄漏。很抱歉造成混乱!

【问题讨论】:

  • 不看代码就很难知道,尽管 js 内存泄漏经常围绕未删除的事件侦听器展开。就您的过度绘制问题而言,您可以将多个画布叠加在一起,并且只重绘需要它的画布(尽管用户只能与顶层交互)。我猜您可能正在重绘 fn 中创建一个闭包,并将您的图像数据重新分配给重复数量的封闭本地变量。
  • “由于他们的工作性质,他们都必须完全重绘”你确定你不能解析更多不需要每帧更新的画布上的绘图吗?这样你就可以使用drawImage(),这是画布上最快的方法之一
  • @JaredSmith 的观点值得挖掘。我也想知道您是否考虑使用 beginPath :您知道如果不这样做,路径会长大吗?显示一些代码,否则很难分辨。
  • 另一个建议:尽量减少你的应用程序,让它什么都不做。你不应该有任何泄漏。现在一一重新启用您的功能,直到它泄漏。
  • @GameAlchemist 有一个很好的观点 - 这将允许您确定实际消耗的来源并允许您进行重构以使事情更加优化。

标签: html canvas memory-leaks html5-canvas web-worker


【解决方案1】:

使用 clearRect 是最好的选择。

你为什么使用 125ms 重绘 vs requestAnimationFrame(这使用了本机滴答声,这也将允许丢帧并有助于提高性能)

我会避免删除 DOM 元素,因为这非常昂贵。

内存总是会增加,我也会检查你的闭包,因为任何不在闭包中的东西都不会被自动垃圾收集,从而导致更多的内存使用。

结帐至statsjs,它会告诉您您的 FPS 并为您提供一些图表。还有Memory Stats,它会显示内存消耗。

我猜你为什么会看到这样的高峰,是因为资源没有被垃圾收集,你的代码可以使用一些优化,但在黑暗中看不到任何重要的东西。

【讨论】:

  • IIRC 封闭的词法变量不能被垃圾收集并不完全正确(尽管它肯定更有问题)。但我怀疑你对泄漏源的看法是正确的。而且您肯定会使用 RequestAnimationFrame。
  • 是的,这不是一个大问题,但根据代码结构和设置方式可能会导致问题。闭包内存的东西是一个建议的优化,一般以及处理在画布上绘制很多东西。
  • 是的,尤其是像图像缓冲区数据这样大的东西。
  • @DrewDahlman 你说的内存总是会增加是什么意思?帆布是正常的吗?不幸的是,我无法共享代码,但我会尝试这些东西并更新结果!
  • 所以内存会上升,直到需要清理,在 JS 中,除了闭包之外,您无法控制(JS 引擎知道不再需要哪些变量和代码片段,因此它将为您自动处理和清理)我可能建议的另一件事是先绘制到实际上不在“屏幕上”的画布,然后将该数据绘制到属于 DOM 的数据中。这也提高了性能。
【解决方案2】:

尝试将动画循环包装在另一个初始化变量的函数中。这样就不会在循环中创建或销毁任何变量。

var aniTimeout = null;

function wrap() {
  
  var can = document.getElementById('can');
  var ctx = can.getContext('2d');
  var x = 0;
  var y = 0;
  var r = 5;
  var colors = ["#FF0000","#009900","#0000FF","#990099","#00CCCC","#FFCC00"];
  var cLen = colors.length;
  var ms = 125;
  
  function ani() {
    ctx.clearRect(0,0,50,200);
    ctx.clearRect(0,0,200,50);
    ctx.clearRect(150,0,200,150);
    ctx.clearRect(0,100,200,150);
    x = Math.floor(Math.random() * 190) + 5;
    y = Math.floor(Math.random() * 140) + 5;
    ctx.fillStyle = colors[Math.floor(Math.random() * cLen)];
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.arc(x,y,r,0,Math.PI*2);
    ctx.fill();
    aniTimeout = setTimeout(ani,ms);
  }
  
  ani();
  
}

wrap();
#can {
  border:1px solid #999999;
}
<canvas id="can" width="200" height="150"></canvas>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    相关资源
    最近更新 更多