当创建使用Web音频API音频缓冲,存在由decodeAudioData方法创建缓冲剂,其驻留在存储器且显然不是通过JavaScript访问。它们似乎在浏览器选项卡的整个生命周期中徘徊,并且永远不会收集垃圾。
我知道这些缓冲区与主线程分开,并在另一个线程上设置以进行异步解码。我也知道,API规范说decodeAudioData不应该被允许进行解码相同的输入缓冲了两次,我以为是为什么解码缓冲器和/或缓冲围绕保持编码输入的副本。但是,在内存受限的设备(例如Chromecast)上,这会导致大量内存积聚,并且Chromecast崩溃。
在我的示例代码中,我使用Ajax获取mp3,然后将arraybuffer传递给encodeAudioData函数。通常,在该函数中有一个成功回调,可以将解码的AudioBuffer作为参数。但是在我的代码中,我什至没有传递它。因此,在对解码后的缓冲区进行解码之后,我也不做任何事情。我的代码中没有任何地方引用它。它完全留在本机代码中。但是,每次对该函数的调用都会增加内存分配,并且永远不会释放它。例如,在Firefox一下:内存显示那里的标签的使用寿命audiobuffers。对于垃圾回收器而言,非引用应该足以摆脱这些缓冲区。
然后我的主要问题是,是否有对这些解码的音频缓冲区的引用,例如在audiocontext对象中,或者我可以尝试从内存中删除它们的其他地方?还是有其他方法可以使这些已存储且无法访问的缓冲区消失?
从所有其他我的问题不同目前SO关于decodeAudioData因为我表明,在内存泄漏甚至发生而无需用户存储的任何附图或甚至使用返回的解码的音频缓冲器中。
function loadBuffer() {
// create an audio context
var context = new (window.AudioContext || window.webkitAudioContext)();
// fetch mp3 as an arraybuffer async
var url = "beep.mp3";
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
request.onload = function () {
context.decodeAudioData(
request.response,
function () {// not even passing buffer into this function as a parameter
console.log("just got tiny beep file and did nothing with it, and yet there are audio buffers in memory that never seem to be released or gc'd");
},
function (error) {
console.error('decodeAudioData error', error);
}
);
};
request.onerror = function () {
console.log('error loading mp3');
}
request.send();
}
答案 0 :(得分:0)
我已经找到了解决网络音频API audiobuffers切换的问题围绕无限期和崩溃的Chromecast和其他移动平台的方法。 [我还没有在所有浏览器测试这一点 - 您的里程可能会有所不同。 ]]
注意事项:您必须决定何时使用此清除方法(例如,在加载和播放了如此多的缓冲区之后)。您可以在没有iframe的情况下执行此操作,但是您可能必须重新加载页面一次或两次才能启动垃圾回收。对于需要在内存瘦平台(例如Chromecast或其他移动设备)上加载大量Web Audio API音频缓冲区的用户而言,这是一种务实的解决方法。
function hack_memory_management() {
var frame_player = document.getElementById("castFrame");
//sample is the object which holds an audio_context
frame_player.contentWindow.sample.clearBuffers();
setTimeout(function () {
frame_player.contentWindow.location.reload();
}, 1000);
}
CrossfadeSample.prototype.clearBuffers = function () {
console.log("CLEARING ALL BUFFERS -IT'S UP TO GC NOW'");
// I have four of each thing because I am doing four part harmony
// these are the decoded audiobuffers used to be passed to the source nodes
this.soprano = null;
this.alto = null;
this.tenor = null;
this.bass = null;
if (this.ctl1) {
//these are the control handles which hold a source node and gain node
var offName = 'stop';
this.ctl1.source[offName](0);
this.ctl2.source[offName](0);
this.ctl3.source[offName](0);
this.ctl4.source[offName](0);
// MAX GARGABE COLLECTION PARANOIA
//disconnect all source nodes
this.ctl1.source.disconnect();
this.ctl2.source.disconnect();
this.ctl3.source.disconnect();
this.ctl4.source.disconnect();
//disconnect all gain nodes
this.ctl1.gainNode.disconnect();
this.ctl2.gainNode.disconnect();
this.ctl3.gainNode.disconnect();
this.ctl4.gainNode.disconnect();
// null out all source and gain nodes
this.ctl1.source = null;
this.ctl2.source = null;
this.ctl3.source = null;
this.ctl4.source = null;
this.ctl1.gainNode = null;
this.ctl2.gainNode = null;
this.ctl3.gainNode = null;
this.ctl4.gainNode = null;
}
// null out the controls
this.ctl1 = null;
this.ctl2 = null;
this.ctl3 = null;
this.ctl4 = null;
// close the audio context
if (this.audio_context) {
this.audio_context.close();
}
// null the audio context
this.audio_context = null;
};
遗憾的是,即使这样做仍然无法可靠地工作,并且在清除了一些新的mp3之后,Chromecast仍然可能崩溃。看“我的本解决方案”别处此页面上。
答案 1 :(得分:0)
当您将每个音频标签路由到Web音频图中(通过使用MediaElementAudioSourceNode)时,是否可以在Chromecast上使用多个音频标签?
答案 2 :(得分:0)
我找不到使用Web Audio API并同时播放四个mp3(用于四声部和声)的Chromecast的最终令人满意的解决方案。第二代似乎根本没有足够的资源来容纳音频缓冲区,并同时使用decodeAudioData解码四个mp3文件,而不会留下太多的垃圾并最终导致崩溃。我决定使用基于Web Audio API构建的surikov的webaudiofont,并使用midi文件。在台式机浏览器或具有更多资源的其他设备上,我从来没有遇到过问题,但是我必须使它在Chromecast上运行。我现在使用webaudiofont完全没有问题。
答案 3 :(得分:0)
我面临着同样的问题。最终对我有用的是断开连接并删除所有连接的资源:
if (this.source) {
this.source.disconnect()
delete this.source
}
if (this.gain) {
this.gain.disconnect()
delete this.gain
}
await this.audioContext.close()
delete this.audioContext
delete this.audioBuffer
仅关闭audioContext是不够的。似乎引用将继续存在,以防止垃圾收集。