Jump to content

Audio + memory usage = headache


Anderberg
 Share

Recommended Posts

Does anyone know how to unload and destroy audio files appropriately?

I have about 12 MB of audio in my game, or about 15 minutes. I do not load all of them at one time, since this will break any mobile browser. So I load them in the states they are needed. About 4 MB is loaded at the same time.

 

According to the Task Manager in chrome, the memory used by my game just keeps growing and growing, easily above 1000MB by changing states. (Browsers decode audio to lossless => memory use is high, regardless of file format and encoding.)

 

In all states I have a shutdown function that destroys all the sounds and purges audio loaded in the cache. This is my current code (very similar to how cache is cleared when changing states, but I have some assets I use everywhere and don't want to remove):

function clearCache () {  // Purge sound.  var key = this.sound._sounds.length;  while (key--) {    this.sound._sounds[key].destroy(true);  }  // Destroy "everything" in cache.  for (var i = 0; i < this.cache._cacheMap.length; i++) {    var cache = this.cache._cacheMap[i];    for (key in cache) {      if (key !== '__default' && key !== '__missing' && this.cache._doNotDelete.indexOf(key) < 0) {        if (cache[key].destroy) {          cache[key].destroy();        }      delete cache[key];      }    }  }}

(Note: This problem did not occur in previous Phaser versions, so I am suspecting that some reference to the audio files are lingering, but can't find out where.)

 

Also, if anyone has a good way of profiling and debugging browser audio, please share, I haven't found a good way to figure out where all this memory goes (Chrome heap profiler says that I use | 20MB).

Link to comment
Share on other sites

Sounds very familiar. In our project that had three tracks for menus and one+sound effects for the actual game, memory usage rocketed to 1200mb in menus and in game it dropped to 700-800mb. Then when returning from game to menu, garbace collector wasn't fast enough to clear memory although cache was indeed cleared. This caused game to use something like 700mb+1200mb of memory effectively crashing any browser. In chrome it just trew oh snap and on firefox caused decoding error. Other issues with web audio were very long loading times, random decoding errors, horrible performance, memory leaks and so on. Like with you, cache was cleared between states, both maually and with state.start(X,true,true).
I'm sorry that I can't really help you with this as in the end we scraped both web audio and phaser sound system and switched to use vanilla JS new Audio() method. This actually removed whole bunch of issues in the project, including abyssal memory usage.

 

EDIT: there is also option in Phaser sound manager to use audio tag which might fix some of your issues. I haven't personally tested it but I sort of guess that it still uses same methods and properties as with web audio and therefore saving the effort of rewriting your code f you wan't to try it out.

Link to comment
Share on other sites

RedPanduzer: Even though you didn't find a solution for web audio it is somehow good to hear that I am not the only one with this problem :)

My memory usage should peak at about 400-500MB (using web audio) and go back down to 250-300. At least that is what happened in earlier Phaser versions.

 

Thanks for the tip about not using web audio. I will experiment a bit to see if it will fix it for me! I've read up before that audio tags can only play one at the time, but perhaps that has changed, I'll try it out none the less.

Link to comment
Share on other sites

  • 2 weeks later...

I still haven't found a solution for this problem, so I created an isolated test case and hope that someone can confirm the same problem.

v2.4.4 - https://dl.dropboxusercontent.com/u/116813451/PhaserSoundTest/index_v2.4.4.html

v2.3.0 - https://dl.dropboxusercontent.com/u/116813451/PhaserSoundTest/index_v2.3.0.html

v2.4.4 decode w/o play - https://dl.dropboxusercontent.com/u/116813451/PhaserSoundTest/indexDecodeOnly_v2.4.4.html

- Open a task manager and watch the memory usage grow (chrome/webkit).

 

What I have noticed so far:
1) It is somewhere between v2.3.0 and v2.4.0a when running web audio.

2) Only in Chrome on my desktop, and in Safari on the iPad, so I'm guessing it is webkit related.

3) Creating sound objects seems to be what keeps the memory stuck. I don't know how yet. I found this out by not creating a sound object in the states. Decoding is still done, but memory is freed when changing states.
(Note: Decoding is what uses up a lot of memory. Decoding is done automatically if not specifically told not to when loading the audio. If you say so, decoding will be done when the sound is played instead, with the same effect.)

Link to comment
Share on other sites

Finally I seem to have found it.

In, at least Chrome, there is a memory leak bug when you try to stop and disconnect an AudioBufferSouceNode at the same time. This behaviour was introduced in Phaser with this commit:

https://github.com/photonstorm/phaser/commit/1990bce48b82b85b487cac0b0f990caede4d8c2d

 

A fix that seems to work is to move the disconnect parts to the onendedhandler.

if (this.externalNode){    this._sound.disconnect(this.externalNode);}else{    this._sound.disconnect(this.gainNode);}

*if you force restart audio with the play function you might need another solution.

 

Working demo: https://dl.dropboxusercontent.com/u/116813451/PhaserSoundTest/indexFix_v2.4.4.html

Link to comment
Share on other sites

  • 8 months later...
  • 5 months later...

Hi @trpzn

I have the code here. I hope @Anderberg doesn't mind since he made it available before:

/* Fix for Phaser to properly remove music cache START */
Phaser.Sound.prototype.onEndedHandler = function () {
    this._sound.onended = null;
    this.isPlaying = false;
    this.stop();

    if (this.externalNode)
    {
        this._sound.disconnect(this.externalNode);
    }
    else
    {
        this._sound.disconnect(this.gainNode);
    }
};

Phaser.Sound.prototype.stop = function () {

   if (this.isPlaying && this._sound)
   {
       if (this.usingWebAudio)
       {
           if (typeof this._sound.stop === 'undefined')
           {
               this._sound.noteOff(0);
           }
           else
           {
               try {
                   this._sound.stop(0);
               }
               catch (e)
               {
                   //  Thanks Android 4.4
               }
           }
       }
       else if (this.usingAudioTag)
       {
           this._sound.pause();
           this._sound.currentTime = 0;
       }
   }

   this.pendingPlayback = false;
   this.isPlaying = false;
   var prevMarker = this.currentMarker;

   if (this.currentMarker !== '')
   {
       this.onMarkerComplete.dispatch(this.currentMarker, this);
   }

   this.currentMarker = '';

   if (this.fadeTween !== null)
   {
       this.fadeTween.stop();
   }

   if (!this.paused)
   {
       this.onStop.dispatch(this, prevMarker);
   }

};
/* Fix for Phaser to properly remove music cache END */


This works fine for my project which is in Phaser version 2.6.2. As far as I know it is still an open issue, I have to assume not many people have run into this issue before but when you are making big games like mine which is over an hour long you need to be able to ditch the audio easily :)

Hope that helps.

Link to comment
Share on other sites

  • 11 months later...

Hi all.

i have a problem with memory leak.

I try take heap snapshot of my game on Chrome.

I saw:

- if i load audio in preload function, my State and phaser StateManager is load again each time i reload webpage. So, memory keep increasing

- If i don't load audio. Memory doesn't increase.

@Anderberg @fitness23 can you help me? How to use your code? I uploaded my code,  with screenshot of snapshot. Please take a look. Thank you so much.

memory_leak.zip

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...