Javascript 重复应用d3转换导致内存泄漏
我有一个SVG地图和一个间隔,用于轮询数据更改并相应地更新地图上的颜色。这一切都很好,除非我使用一个过渡淡入新的颜色。然后选项卡慢慢地消耗越来越多的内存,直到崩溃 我制作了一个简化的示例,显示了相同的行为:Javascript 重复应用d3转换导致内存泄漏,javascript,d3.js,memory-leaks,Javascript,D3.js,Memory Leaks,我有一个SVG地图和一个间隔,用于轮询数据更改并相应地更新地图上的颜色。这一切都很好,除非我使用一个过渡淡入新的颜色。然后选项卡慢慢地消耗越来越多的内存,直到崩溃 我制作了一个简化的示例,显示了相同的行为: var size = 500; var num = 25; var boxSize = size / num; function color(d) { return '#' + Math.random().toString(16).slice(2,8); } var svg =
var size = 500;
var num = 25;
var boxSize = size / num;
function color(d) {
return '#' + Math.random().toString(16).slice(2,8);
}
var svg = d3.select('body')
.append("svg")
.attr("width", size)
.attr("height", size);
var squares = svg.selectAll(".square")
.data(d3.range(num * num))
.enter().append("rect")
.attr("class", "square")
.attr("width", boxSize)
.attr("height", boxSize)
.attr("x", function (d) { return boxSize * (d % num);})
.attr("y", function (d) { return boxSize * Math.floor(d / num); })
.style("fill", color);
function shuffleColors() {
squares.interrupt().transition().duration(500).style("fill", color);
timer = setTimeout(shuffleColors, 1000);
}
var timer = setTimeout(shuffleColors, 1000);
我已经在Linux上的Chromium(49)和Firefox(45)中试过了。前者似乎爆发得更快,但两者都有问题。在这两种情况下,它都不会显示在内存探查器中,但关于:内存显示选项卡正在增长
我从文档中了解到,将转换添加到选择中会用相同的名称替换以前的任何转换(包括空名称),但我的假设是,为实现转换而创建的函数实际上不会被抛出。但我还没有设法让他们证实这一点,也没有解决这个问题
因此,问题分为两部分:
d3\u-selectionPrototype.transition
每次都以递增的ID创建一个新的d3\u-transition
,但如果旧的转换被垃圾收集,这也没关系。我仍然无法指出它是否被保留或为什么被保留我相当确定它必须在这里做这件事:
function shuffleColors() {
squares.interrupt().transition().duration(500).style("fill", color);
timer = setTimeout(shuffleColors, 1000);
}
var timer = setTimeout(shuffleColors, 1000);
每次调用函数shuffleColors()
,它都会再次调用自身,本质上创建一个没有基本大小写的递归循环。它没有立即爆炸的原因是它每次调用函数都延迟了1000毫秒,然而,我认为squares.interrupt().transition().duration(500.style)(“fill”,color)需要更长的时间代码>完成,而不是调用setTimeout()
。因此,即使你称之为每1000毫秒一次,它也可能以某种方式堆积起来,因为某些颜色变化可能需要更多的时间来处理
虽然它在技术上不应该这样做,但知道JavaScript是多么异步,它可能会扮演一个角色。我建议改为这样做,并报告结果:
function shuffleColors() {
squares.interrupt().transition().duration(500).style("fill", color);
}
var timer = setInterval(shuffleColors, 1000);
如果需要,您还可以随时调用clearInterval(timer)
setInterval()
创建的原因正是您实现的setTimeout()
编辑:这可能不完全有效,因为您可能仍然需要等待颜色更改完成,但是,这至少是一种更干净的方法。您可以实现某种wait()
函数来等待颜色更改完成
尽管矢量(SVG)图像是轻量级的,但与解码JPEG图像相比,不断改变颜色或类似内容所需的处理量是巨大的
如果将原始图像的大小减小很多,然后将其扩展到您的分辨率,您可能会发现更好的结果。您可以制作一个100x100画布SVG,并将其扩展到2000x2000或其他,这样它就不必绘制如此大的图像。我只是在您的shuffle colors函数中添加了一个调试器关键字,然后将其添加到D3代码中。它对调用中断所做的第一件事就是开始设置1600个中断的列表,它将每个方块作为一个单独的实体进行处理。我没有深入讨论,因为问题很明显,你正在大量地咀嚼内存,当GC开始启动时,减速将使setInterval停止,一旦发生这种情况,你只是在等待崩溃。使用setTimeout并在完成后开始下一次洗牌。没有泄漏内存您正在溢出您的调用堆栈我正要对interrupt()
说同样的话。对我来说可能的重复至少我无法复制,live JS堆内存增长到45MB左右,然后在GC启动时下降到~32MB,然后再无限增长。请参阅副本的答案。