首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >移动平台上的Web Audio API内存泄漏

移动平台上的Web Audio API内存泄漏
EN

Stack Overflow用户
提问于 2014-06-09 19:50:01
回答 2查看 3.1K关注 0票数 14

我正在开发一个将大量使用Audio的应用程序,我正处于研究阶段,以决定是否在支持它的设备上使用Web Audio API。我已经组装了一个非常简单的测试台,它加载了一个MP3精灵文件(大约600kB),有一个播放和暂停按钮,还有一个销毁按钮,理论上应该允许GC回收Web Audio API实现所使用的内存。然而,在加载和销毁~5次iOS后,由于内存不足异常而崩溃。

我已经在XCode Instruments中分析了MobileSafari,MobileSafari确实不断地消耗内存。此外,600kb的MP3在解码时需要大约80-90MB的内存。

我的问题是-当使用Web audio API解码音频数据时,为什么内存使用量如此之大,而且为什么内存从未回收?根据我的理解,解码是浏览器的异步操作,因此可能发生在单独的线程上?有没有可能浏览器的独立线程永远不会释放解码过程中使用的内存?

我的代码如下,任何帮助/解释都非常感谢:

代码语言:javascript
运行
复制
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Web Audio Playground</title>
</head>
<body>
<button id="load">
    Load
</button>
<button id="play">
    Play
</button>
<button id="pause">
    Pause
</button>
<button id="destroy">
    Destroy
</button>
<script type="application/javascript">
    (function () {
        window.AudioContext = window.AudioContext || window.webkitAudioContext;

        var loadButton = document.getElementById('load'),
                playButton = document.getElementById('play'),
                pauseButton = document.getElementById('pause'),
                destroyButton = document.getElementById('destroy'),
                audioContext = new window.AudioContext(),
                soundBuffer = null,
                soundSource = null;

        loadButton.addEventListener('click', function () {
            var request = new XMLHttpRequest();
            request.open('GET', 'live-sprite.mp3', true);
            request.responseType = 'arraybuffer';

            // Decode asynchronously
            request.onload = function () {
                audioContext.decodeAudioData(request.response, function (buffer) {
                    soundBuffer = buffer;
                });
            };
            request.send();
        });

        playButton.addEventListener('click', function () {
            soundSource = audioContext.createBufferSource();
            soundSource.buffer = soundBuffer;
            soundSource.connect(audioContext.destination);
            soundSource.start(0);
        });

        pauseButton.addEventListener('click', function () {
            if (soundSource) {
                soundSource.stop(0);
            }
        });

        destroyButton.addEventListener('click', function () {
            if (soundSource) {
                soundSource.disconnect(0);
                soundSource = null;
                soundBuffer = null;
                alert('destroyed');
            }
        });
    })();

</script>
</body>
</html>
EN

回答 2

Stack Overflow用户

发布于 2015-09-14 23:53:39

我在SoundJS issue tracker上发布了关于这一点的帖子,但我将在这里重申一下,供任何想要查看的人使用:

在iOS Safari上,简单地断开连接和取消引用AudioBufferSourceNode对象似乎是不够的;您需要手动清除对其缓冲区的引用,否则缓冲区本身就会泄漏。(这意味着AudioBufferSourceNode obj本身会泄漏,但在我们的项目中,这并不是一个实际的限制。)

不幸的是,要做到这一点,需要创建一个包含1个样本的长暂存缓冲区,因为将其赋值为null会导致异常。语句也必须是try-catch包装的,因为当.buffer被重新赋值时,Chrome/FF将在任何时候抛出。

有效的解决方案是:

代码语言:javascript
运行
复制
var ctx = new AudioContext(),
    scratchBuffer = ctx.createBuffer(1, 1, 22050);

class WebAudioAdapter extends AudioAdapter {
    close() {
        if( this.__src ) {
            this.__src.onended = null;
            this.__src.disconnect(0);
            try { this.__src.buffer = scratchBuffer; } catch(e) {}
            this.__src = null;
        }
    }
}

希望这对你们也有帮助!

票数 4
EN

Stack Overflow用户

发布于 2014-08-26 23:25:48

内存之所以很大,是因为Web Audio API将您的小MP3解码为32位LPCM -这将为您提供大约每分钟10MB的内容。

因此,一个4分钟的立体声MP3最终大约是80MB。

只要您的应用程序仍保留已解码的AudioBuffer,就不能回收此内存。因此,只要有对它的引用(在本例中为soundBuffer),该内存就不能被释放。如果是的话,你就不能回放音频了。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24119684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档