【发布时间】:2026-02-06 04:40:01
【问题描述】:
我有一个 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) 中尝试过。前者似乎爆炸得更快,但这对两者都是一个问题。它既没有显示在内存分析器中,但 about:memory 显示选项卡正在增长。
我从文档中的理解是,向选择添加过渡会用相同的名称替换任何先前的过渡(包括空名称),但我的假设是为实现过渡而创建的函数实际上并没有被丢弃.但我还没有设法让他们确认或解决这个问题。
所以,一个两部分的问题:
- 这是对 d3 转换的正确使用,还是有更正确的方法来做我想做的事情?
- 如果我正确使用了转换,如何让它停止泄漏内存?
编辑:
- 根据 Blindman67 的评论,我将其更改为使用 setTimeout 并稍微小一些。我试图模拟的原件更小更慢,但需要数小时才能最终变大,所以我试图加快速度。这个版本似乎仍在增长,至少对 Chromium 上的我来说是这样。
- 据我观察,
d3_selectionPrototype.transition每次都会创建一个新的d3_transition,其 ID 会递增,但如果旧的被垃圾收集就可以了。而且我仍然无法指出它是否或为什么会被保留。
【问题讨论】:
-
我刚刚在您的 shuffle Colors 函数中添加了一个 debugger 关键字,并将其添加到 D3 代码中。它在调用中断上做的第一件事是开始设置一个包含 1600 个中断的列表,它将每个方格作为一个单独的实体处理。我没有更深入,因为问题很明显,您正在大块地咀嚼内存,当 GC 确实开始减速时,会将 setInterval 退出,一旦发生这种情况,您就在等待崩溃。完成后使用 setTimeout 并开始下一次随机播放。不泄漏内存,您正在溢出调用堆栈
-
我正要对
interrupt()说同样的话。 -
对我来说至少我无法重现,实时 JS 堆内存增长到大约 45MB,然后在 GC 启动时下降到 ~32MB,然后再次增长,无限。查看副本的答案。
标签: javascript d3.js memory-leaks