网络音频 API 内存泄漏
Web Audio API Memory Leak
一个web-audio-apiAudioNode应该如何清理以释放它的内存?我正在调用 oscillatorNode.stop()
并且 oscillatorNode.disconnect()
基于 , but it doesn't seem to help, and I end up with memory leaks. This post 不适用,因为我在停止振荡器节点后立即删除引用。
我创建了一个显示该问题的示例网站。以下是重现的步骤。
- 在打开开发工具的台式机或笔记本电脑上 html 创建本地 html 文件和 运行 下面的代码片段 chrome。
- 创建堆快照。
- 单击 "Go" 按钮。
- 定期创建另一个堆快照。
- 请注意,即使在垃圾收集器 运行 之后,内存仍在继续增加。 为什么?
<html>
<body>
<button onclick="go()">Go</button>
<button onclick="cancel=true">Cancel</button>
<div id="status"></div>
<script>
var cancel = false;
var statusEl = document.getElementById('status');
async function go() {
cancel = false;
for (var i = 0; i < 100000; i++) {
if (cancel) {
return;
}
statusEl.innerHTML = i;
play();
await new Promise((resolve) => { setTimeout(resolve, 1); });
stop();
}
}
var ctx = new AudioContext();
var data = {
oscillatorNode: null
};
function play() {
if (!data.oscillatorNode) {
// create an oscillator
data.oscillatorNode = ctx.createOscillator();
data.oscillatorNode.frequency.value = 220.0;
data.oscillatorNode.connect(ctx.destination);
data.oscillatorNode.start(ctx.currentTime);
}
}
function stop() {
if (data.oscillatorNode) {
data.oscillatorNode.stop();
data.oscillatorNode.disconnect();
delete data.oscillatorNode;
}
}
</script>
</body>
</html>
根据 this post, "When the oscillator stops it should automatically disconnect itself from any downstream nodes". However, due to this bug in chrome (thanks James Lawruk 的发现),它实际上并没有自行清理。
该错误报告中的 This comment 提到
The issue is that because disconnect() is called right after stop(), the oscillator is disconnected from the destination, so any processing associated with stop() is never done. This also includes not actually stopping the oscillator because it takes at least one render quantum to do that. Since it was disconnected, that render quantum never happens.
考虑到这一点,我附加到 oscillatorNode.onended
事件并在该回调中调用断开连接,不再有内存泄漏!
代码如下:
function stop() {
return new Promise((resolve) => {
//whenever the node actually finishes playing, disconnect it
data.oscillatorNode.onended = function () {
data.oscillatorNode.disconnect();
delete data.oscillatorNode;
resolve();
}
//stop the oscillator
data.oscillatorNode.stop();
});
}
以及堆快照:
717528 bug 中的评论说:
The issue is that because disconnect() is called right after stop(),
the oscillator is disconnected from the destination, so any processing
associated with stop() is never done. This also includes not actually
stopping the oscillator because it takes at least one render quantum
to do that. Since it was disconnected, that render quantum never
happens.
因此,如果您在调用 disconnect() 之前添加延迟,它应该保持一致的内存级别。
function stop() {
if (data.oscillatorNode) {
data.oscillatorNode.stop();
var oscillatorNode = data.oscillatorNode;
setTimeout(function() {
oscillatorNode.disconnect();
delete oscillatorNode;
}, 100);
}
}
一个web-audio-apiAudioNode应该如何清理以释放它的内存?我正在调用 oscillatorNode.stop()
并且 oscillatorNode.disconnect()
基于
我创建了一个显示该问题的示例网站。以下是重现的步骤。
- 在打开开发工具的台式机或笔记本电脑上 html 创建本地 html 文件和 运行 下面的代码片段 chrome。
- 创建堆快照。
- 单击 "Go" 按钮。
- 定期创建另一个堆快照。
- 请注意,即使在垃圾收集器 运行 之后,内存仍在继续增加。 为什么?
<html>
<body>
<button onclick="go()">Go</button>
<button onclick="cancel=true">Cancel</button>
<div id="status"></div>
<script>
var cancel = false;
var statusEl = document.getElementById('status');
async function go() {
cancel = false;
for (var i = 0; i < 100000; i++) {
if (cancel) {
return;
}
statusEl.innerHTML = i;
play();
await new Promise((resolve) => { setTimeout(resolve, 1); });
stop();
}
}
var ctx = new AudioContext();
var data = {
oscillatorNode: null
};
function play() {
if (!data.oscillatorNode) {
// create an oscillator
data.oscillatorNode = ctx.createOscillator();
data.oscillatorNode.frequency.value = 220.0;
data.oscillatorNode.connect(ctx.destination);
data.oscillatorNode.start(ctx.currentTime);
}
}
function stop() {
if (data.oscillatorNode) {
data.oscillatorNode.stop();
data.oscillatorNode.disconnect();
delete data.oscillatorNode;
}
}
</script>
</body>
</html>
根据 this post, "When the oscillator stops it should automatically disconnect itself from any downstream nodes". However, due to this bug in chrome (thanks James Lawruk 的发现),它实际上并没有自行清理。
该错误报告中的This comment 提到
The issue is that because disconnect() is called right after stop(), the oscillator is disconnected from the destination, so any processing associated with stop() is never done. This also includes not actually stopping the oscillator because it takes at least one render quantum to do that. Since it was disconnected, that render quantum never happens.
考虑到这一点,我附加到 oscillatorNode.onended
事件并在该回调中调用断开连接,不再有内存泄漏!
代码如下:
function stop() {
return new Promise((resolve) => {
//whenever the node actually finishes playing, disconnect it
data.oscillatorNode.onended = function () {
data.oscillatorNode.disconnect();
delete data.oscillatorNode;
resolve();
}
//stop the oscillator
data.oscillatorNode.stop();
});
}
以及堆快照:
717528 bug 中的评论说:
The issue is that because disconnect() is called right after stop(), the oscillator is disconnected from the destination, so any processing associated with stop() is never done. This also includes not actually stopping the oscillator because it takes at least one render quantum to do that. Since it was disconnected, that render quantum never happens.
因此,如果您在调用 disconnect() 之前添加延迟,它应该保持一致的内存级别。
function stop() {
if (data.oscillatorNode) {
data.oscillatorNode.stop();
var oscillatorNode = data.oscillatorNode;
setTimeout(function() {
oscillatorNode.disconnect();
delete oscillatorNode;
}, 100);
}
}