Javascript 重复应用d3转换导致内存泄漏

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 =

我有一个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转换的正确使用,还是有更正确的方法来实现我的目标
  • 如果我正确地使用了转换,如何让它停止内存泄漏
  • 编辑:

  • 根据Blindman67的评论,我将其更改为使用setTimeout,并稍微小一点。我试图模拟的原版更小、更慢,但它需要几个小时才能真正变大,所以我试图加快速度。这个版本似乎仍在增长,至少对我来说是在铬上
  • 我观察到,
    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,然后再无限增长。请参阅副本的答案。