Проблема
При создании аудио-буферов с использованием Web Audio API, есть буферы, созданные методом decodeAudioData, которые находятся в памяти и, по-видимому, недоступны через JavaScript.Кажется, они всю жизнь тянутся на вкладке браузера и никогда не собирают мусор.
Возможная причина проблемы
Я знаю, что эти буферы отделены от основного потока и установлены в другом потоке для асинхронного декодирования.Я также знаю, что спецификация API говорит, что decodeAudioData не должно быть позволено декодировать один и тот же входной буфер дважды, что я предполагаю, поэтому копия декодированного буфера и / или закодированный входной буфер хранятся вокруг.Однако на устройствах с ограниченной памятью, таких как Chromecast, это приводит к накоплению огромных объемов памяти и сбоям Chromecast.
Воспроизводимость
В моем примере кода я получаю mp3, используя Ajax, а затем передаю буфер массивав функцию decodeAudioData.Обычно внутри этой функции существует обратный вызов onsuccess, который может принимать декодированный AudioBuffer в качестве параметра.Но здесь, в моем коде, я даже не передаю это. Поэтому я также ничего не делаю с декодированным буфером после его декодирования.На него не ссылаются нигде в моем коде.Это полностью оставлено в нативном коде.Однако каждый вызов этой функции увеличивает выделение памяти и никогда не освобождается.Например, в Firefox about: memory показывает аудиобуферы там для жизни Tab.Без ссылки должно быть достаточно, чтобы сборщик мусора избавился от этих буферов.
Мой главный вопрос в том, есть ли какая-либо ссылка на эти декодированные аудиобуферы, скажем, в объекте аудиоконтекста или где-то еще?иначе что я могу попытаться удалить их из памяти?Или есть какой-то другой способ, которым я могу заставить эти сохраненные и недоступные буферы исчезнуть?
Мой вопрос отличается от всех других в настоящее время на 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();
}
Чтобы предвидеть некоторые возможные ответы.
- Я должен использовать API Web Audio, потому что я играю гармонию четырех партий из четырех аудиофайлов в Chromecast, а элемент html audio не поддерживает одновременное воспроизведение нескольких файлов в Chromecast.
- Вероятно, любая библиотека JS, на которую вы можете сослаться [например, Howler.js, Tone.js, Amplitude.js и т. Д.], Построена на Web Audio API, и поэтому все они будут иметь общую проблему утечки памяти.
- Я знаю, что WAA зависит от реализации для каждого браузера.На данный момент я больше всего беспокоюсь о Chromecast, но проблема существует для каждого браузера, который я пробовал.
- Поэтому, я думаю, что это проблема, связанная со спецификацией, когда спецификации требуется правило недопущения кодирования, и поэтому разработчики хранят копии буфера в потоке уровня браузера, чтобы они могли проверять их по новым входным данным xhr.,Если писатель спецификаций случайно прочитал мой вопрос, не существует ли способа, чтобы пользователь мог иметь опцию для этого поведения и отказаться от нее, если он хочет, чтобы предотвратить внутреннее буферное хранилище на мобильных платформах и платформах с тонкой памятью?
- Мне не удалось найти ссылки на эти буферы ни в одном объекте JS.
- Я знаю, что могу выполнить audio_context.close (), а затем надеюсь на сборку мусора всех ресурсов, содержащихся в audio_context, и затем надеюсь, что смогу заново создать экземпляр audio_context с новым, но это не было эмпирическибыло достаточно своевременно для моего заявления.Сбой Chromecast до того, как GC вывезет мусор.