Chrome快速内存泄漏。运行Javascript Profiler时如何调试修复泄漏?

时间:2014-05-07 18:22:34

标签: javascript html5 google-chrome canvas memory-leaks

我正在使用画布制作游戏,并且遇到了我无法确定的奇怪的Chrome行为。有时当我加载游戏时,Chrome任务管理器会报告它每秒分配+ 300MB,在大约10秒左右的时间内增加到几GB的内存,并且在选项卡崩溃之前它不会停止

当我尝试运行javascript探查器时,问题就会停止。当我运行探查器加载选项卡时,它非常稳定。当问题发生时,然后我启动探查器,它将立即从1.5GB变为稳定的40MB。堆快照向我展示了如果游戏稳定运行我会期待什么。

我的游戏正在window.setInterval上运行(我已经尝试了requestAnimationFrame并且递归setTimeout并且问题仍然存在),并且更频繁地将其设置为高,这意味着当我将游戏设置为30FPS时,这很少发生,当我将其设置为60FPS时,它发生的时间超过一半。这只发生在Chrome上,Firefox看起来很好。

如果Chrome只在分析器运行时才进行垃圾回收,我该如何调试呢?

此外,我注意到当我将FPS推到60时,我的一些动画和键盘输入有点滑稽。我认为这可能是相关的,但在Firefox中也是如此。

3 个答案:

答案 0 :(得分:5)

JavaScript是单线程的,这意味着所有工作都需要在同一个线程上完成,包括排队事件(来自setTimeout / rAF,键等),渲染到画布等等。

如果循环非常紧张(按时间预算),浏览器根本没有任何空间来执行GC等其他任务 - 对于Chrome来说,这项任务似乎是次要的,而Firefox则提供了更高的优先级(可能会从其引擎中获得更多性能)。基本上,正在运行的代码将阻止浏览器执行除执行代码本身以外的其他操作。

这方面的一个很好的指标是当你降低FPS时留下更多空间用于事件队列,清理等。当探查器运行时获得更多优先级以便捕获所有类型的东西所以出于某种原因,GC会进入"潜行"在早期分析器运行时(缺乏更好的术语)。但这是特定于浏览器的,我不知道每个潜在的细节。

如果浏览器无法清除事件队列中的事件,它最终会叠加,最坏的情况是阻止/冻结/崩溃浏览器。

在任何情况下,由于您无法以编程方式访问内存或CPU使用情况等,因此很难对此进行调试(出于针对性的原因)。

最接近的是在循环内部代码的开头和结尾使用高分辨率计时器,看它是否接近帧速率时间。

例如:

function loop() {

    var startTime = performance.now();

    ... other code ...

    var innerLoopTime = performance.now() - startTime;

    requestAnimationFrame(loop);
}

如果你的帧速率是60 FPS,那么每帧的时间将是1000/60,或大约16.667ms。

如果您的innerLoopTime非常接近这个时间,您将知道需要优化循环内执行的代码,或降低帧速率。

您可以使用调试器在函数内获取每步的时间成本,但调试器本身会增加总计的开销。所以测量时间,但成本较低..无论如何扭曲并转向这一点,都将是一个妥协的问题。

答案 1 :(得分:2)

我发现javascript代码中存在大量内存泄漏通常是closures。 如果您正在访问在外部声明的setInterval中的变量,那么您很可能会泄漏一些内存。至于这是否是问题的实际根本原因是另一个问题。

如果您想更多地了解闭包以及它们如何影响您的js的性能,请查看IBM关于该主题的this article。它提供了很好的示例和方法来避免使用它们的内存泄漏,以及一些其他可能的内存泄漏源。

答案 2 :(得分:1)

我们注意到chrome + canvas并不像firefox + canvas那样高效。至于当你打开chrome dev工具时发生的GC,我猜你可能有一些代码可以用正确的方式轻轻地执行GC。你有某种窗口调整大小处理程序吗?可能还有其他东西正在做类似的事情。

当有疑问时,将代码一分为二,直到它不再发生为止。