移动平台上的Web音频API内存泄漏 [英] Web Audio API Memory Leaks on Mobile Platforms

查看:81
本文介绍了移动平台上的Web音频API内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个将大量使用音频的应用程序,并且我正在研究是否要在可以支持它的设备上使用Web Audio API的研究阶段.我整理了一个非常简单的测试台,可以加载MP3 Sprite文件(大小约为600kB),具有播放和暂停按钮以及销毁按钮,从理论上讲,这应该允许GC回收Web Audio API实现所使用的内存.但是,在加载和销毁大约5次后,由于内存不足异常,iOS崩溃了.

I am working on an application that will be using Audio quite heavily and I am in the research stages of deciding whether to use Web Audio API on devices that can support it. I have put together a very simple test bed that loads an MP3 sprite file (~600kB in size), has a play and pause button and also a destroy button, which should in theory allow GC reclaim the memory used by the Web Audio API implementation. However, after loading and destroying ~5 times iOS crashes due to an out of memory exception.

我在XCode Instruments中分析了MobileSafari,实际上MobileSafari一直在消耗内存.此外,解码后600kb的MP3占用约80-90MB的内存.

I have profiled MobileSafari in XCode Instruments and indeed MobileSafari continually eats up memory. Furthermore the 600kb MP3 turns out to use ~80-90MB of memory when decoded.

我的问题是-使用Web Audio API解码音频数据时,为什么内存使用量如此之大,以及为什么从未回收内存?根据我的理解,解码是浏览器的异步操作,因此大概发生在单独的线程上吗?浏览器的单独线程是否有可能永远不会释放解码期间使用的内存?

My question is - When decoding audio data using Web Audio API, why is the memory usage so big and also why is the memory never reclaimed? From my understanding the decoding is an async operation for the browser and so presumably happens on a separate thread? Is it possible the browsers separate thread is never releasing the memory used during decoding?

下面是我的代码,非常感谢您的帮助/解释:

My code is below, any help/explanation is greatly appreciated:

<!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>

推荐答案

我在SoundJS问题跟踪器有关此信息,但在这里我会针对任何正在寻找它的人进行重申:

I made post on SoundJS issue tracker about this, but I'll reiterate it here for anyone looking:

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

It seems that simply disconnecting and dereferencing the AudioBufferSourceNode object on iOS Safari isn't enough; you need to manually clear out the reference to its buffer, or the buffer itself leaks. (This implies the AudioBufferSourceNode obj itself leaks, but we didn't see this as a practical limit in our project.)

不幸的是,需要创建一个1样本长的暂存缓冲区,因为分配为null会导致异常.该语句也必须用try-catch换行,因为在任何时候重新分配.buffer时Chrome/FF都会抛出该异常.

Unfortunately to do this, a 1-sample long scratch buffer needs to get created, as assigning to null will cause an exception. The statement must be try-catch wrapped, too, as Chrome/FF will throw when .buffer is reassigned at any time.

有效的解决方案是:

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;
        }
    }
}

希望这对您也有帮助!

这篇关于移动平台上的Web音频API内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆