Unloading Resources

  ... discussions about development with the GLES1 branch of AndEngine.

Unloading Resources

Postby RealMayo » Wed Nov 30, 2011 9:04 am

Hi guys,
So I've put something together that seems to be working well for unloading all resources in the current scene before I move on to the next scene. I'm just curious what you all think about this? ...

Things I'm unloading are:
Sprites
AnimatedSprites
Shapes
Bodies

So I'm calling either of the following repeatedly as needed until I've unloaded everything...
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.         private void myKillAnimatedSprite(AnimatedSprite mySprite){
  2.                 final PhysicsConnector facePhysicsConnector = this.mPhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(mySprite);
  3.                 this.mPhysicsWorld.unregisterPhysicsConnector(facePhysicsConnector);
  4.                 this.mPhysicsWorld.destroyBody(facePhysicsConnector.getBody());
  5.                 this.mScene.detachChild(mySprite);
  6.         }
  7.  
  8.        
  9.         private void myKillShape(Body myBody, Shape myShape){
  10.                 this.mPhysicsWorld.destroyBody(myBody);
  11.                 this.mScene.detachChild(myShape);
  12.         }
  13.  
  14.  
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


Then I call this at the end...
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.        
  2.         private void myKillOthers(){
  3.                 mScene.clearChildScene();
  4.                 mScene.detachChildren();
  5.                 mScene.reset();
  6.                 mScene.detachSelf();
  7.                 mPhysicsWorld.clearForces();
  8.                 mPhysicsWorld.clearPhysicsConnectors();
  9.                 mPhysicsWorld.reset();
  10.         }
  11.  
  12.         private void myGarbageCollection(){
  13.                 System.gc();                   
  14.         }
  15.  
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


I'm reusing the same mPhysicsWorld and the same Activity when setting the next scene. So because of that I'm not doing mPhysicsWorld.dispose();

So what do you all think of this approach? Like I said, this seems to be working fine. I'm just curious if I'm missing something :?:
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Re: Unloading Resources

Postby RealMayo » Wed Nov 30, 2011 8:42 pm

Another question... What's the best way to check for memory leaks? As in how can I test whether or not I have garbage collected everything perfectly?

Let's say I didn't call any of the methods I mentioned above. Aside from crappy performance, how else can I know if things haven't been unloaded properly?
Thanks
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Re: Unloading Resources

Postby classicwinters » Sat Dec 03, 2011 11:49 pm

Nice code. I'm not sure, but I think you can check the heap and memory usage if you're using eclipse. You can probably be able to chart mem usage v. time to check just how much its leaking. Again I really don't know.
I don't have a lot to show here, but you can follow my twitter if you want : ).

Twitter: https://twitter.com/#!/classicwinters
classicwinters
 
Posts: 16
Joined: Sun Feb 06, 2011 4:20 am

Re: Unloading Resources

Postby RealMayo » Sat Dec 03, 2011 11:51 pm

Thanks :)
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Re: Unloading Resources

Postby thepi » Sun Dec 04, 2011 8:07 am

The code looks perfect for unloading stuff that will not be used anymore in the game.
Otherwise I just move sprites and shapes out of the screen, since I reuse them later in game.

I also read somewhere that using garbage collector is not recommended during game.
Go and trap them... Trap Balls on Google Play
Play & reminisce... Treasure Island LCD Retro
thepi
 
Posts: 456
Joined: Sun Oct 09, 2011 9:30 pm

Re: Unloading Resources

Postby Mathew » Sun Dec 04, 2011 11:41 am

thepi wrote:The code looks perfect for unloading stuff that will not be used anymore in the game.
Otherwise I just move sprites and shapes out of the screen, since I reuse them later in game.

I also read somewhere that using garbage collector is not recommended during game.


Exactly, because often its causing slow downs and generally performance issues.
User avatar
Mathew
 
Posts: 1073
Joined: Sun Jul 31, 2011 2:49 pm
Location: Tarnów, Poland

Re: Unloading Resources

Postby RealMayo » Sun Dec 04, 2011 6:25 pm

Thanks for the tips guys! I hope more people contribute to this thread too, so that we continue a good discussion about how to optimize performance in our apps :)
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Re: Unloading Resources

Postby classicwinters » Sun Dec 04, 2011 7:30 pm

: ). For unloading sound resources, you guys should check out this thread
post25959.html#p25959

CapitanNerd rewrote the classes to remove the sound and music references in the Arraylists that hold them, so they can be GC'd.

The code/fix isn't in the default trunk of the andengine source yet, but its worth implementing if you have some heap problems. It works fairly well, but the code meant for BaseAudioEntity belongs in a different class.
I don't have a lot to show here, but you can follow my twitter if you want : ).

Twitter: https://twitter.com/#!/classicwinters
classicwinters
 
Posts: 16
Joined: Sun Feb 06, 2011 4:20 am

Re: Unloading Resources

Postby RealMayo » Mon Dec 05, 2011 2:24 am

So after much testing, I've revised my code (as seen below). Note that this code is used when the current level (scene) of the game ends and I want to set the next level (scene). Remember that I am reusing the same Activity and the same PhysicsWorld for all levels of my game.

First I declare some variables at the top of my activity. I make them public so that other classes can use them.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.        
  2. public ArrayList<AnimatedSprite> dAnimatedSprite = new ArrayList<AnimatedSprite>();
  3. public ArrayList<Shape> dShape = new ArrayList<Shape>();
  4.  
Parsed in 0.035 seconds, using GeSHi 1.0.8.4


Any time I create a new AnimatedSprite or new Shape, I also call one of the following:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. this.myActivity.dAnimatedSprite.add(myAnimatedSprite);
  2. this.myActivity.dShape.add(myShape);
  3.  
Parsed in 0.035 seconds, using GeSHi 1.0.8.4


So at this point I have loaded ArrayLists with the objects I want to unload later. I will unload Body and Joint a different way (as you'll see below). When I'm ready to unload the current level (scene) of the game and go to the next level (scene) of the game, I do this:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.         private void goToNextLevel(){
  2.                 myGarbageCollection();
  3.                 myLoadScene();
  4.         }
  5.  
  6. private void myGarbageCollection(){
  7.  
  8.         Iterator<Body> allMyBodies = this.mPhysicsWorld.getBodies();
  9.         while(allMyBodies.hasNext())
  10.         {
  11.              try {
  12.                  final Body myCurrentBody = allMyBodies.next();
  13.                  this.runOnUpdateThread(new Runnable(){
  14.                      @Override
  15.                      public void run() {
  16.                          mPhysicsWorld.destroyBody(myCurrentBody);                
  17.                      }
  18.                  });
  19.             } catch (Exception e) {
  20.                 Debug.d(e);
  21.             }
  22.         }
  23.  
  24.         Iterator<Joint> allMyJoints = this.mPhysicsWorld.getJoints();
  25.         while(allMyJoints.hasNext())
  26.         {
  27.              try {
  28.                  final Joint myCurrentJoint = allMyJoints.next();
  29.                  this.runOnUpdateThread(new Runnable(){
  30.                      @Override
  31.                      public void run() {
  32.                          mPhysicsWorld.destroyJoint(myCurrentJoint);                
  33.                      }
  34.                  });
  35.             } catch (Exception e) {
  36.                 Debug.d(e);
  37.             }
  38.         }
  39.                 // check if the ArrayList contains anything
  40.         if(dAnimatedSprite.size()>0){
  41.                 for(int i=0; i < dAnimatedSprite.size(); i++){
  42.                         this.mScene.detachChild(dAnimatedSprite.get(i));
  43.                 }
  44.         }
  45.                 // unload the contents of the ArrayList
  46.         dAnimatedSprite.clear();
  47.                
  48.                 // check if the ArrayList contains anything
  49.         if(dShape.size()>0){
  50.                 for(int i=0; i < dShape.size(); i++){
  51.                         this.mScene.detachChild(dShape.get(i));
  52.                 }
  53.         }
  54.                 // unload the contents of the ArrayList
  55.         dShape.clear();
  56.                        
  57.         mScene.clearChildScene();
  58.         mScene.detachChildren();
  59.         mScene.reset();
  60.         mScene.detachSelf();
  61.         mPhysicsWorld.clearForces();
  62.         mPhysicsWorld.clearPhysicsConnectors();
  63.         mPhysicsWorld.reset();
  64.         mEngine.getFontManager().clear();
  65.  
  66.         System.gc();
  67. }
  68.  
Parsed in 0.044 seconds, using GeSHi 1.0.8.4


That code seems to work well.
What's interesting is while I was testing, I was getting WinDeath errors if I tried to destroy the Bodys and Joints without calling runOnUpdateThread. But I never got those errors when I tried to detach the AnimatedSprites and Shapes without calling runOnUpdateThread. In fact, I experienced some weird behavior if I tried to detach the AnimatedSprites and Shapes by calling runOnUpdateThread.

Anyway, like I said, the above code seems to work well. So you can feel free to try it out, and let me know if you have any comments or suggestions.

Thanks
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Re: Unloading Resources

Postby RealMayo » Tue Dec 13, 2011 5:16 am

Just a little update. I've done even more testing and have refined my code to be more stable. The following code works much better:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. private void myGarbageCollection(){
  2.        
  3.         Iterator<Body> allMyBodies = this.mPhysicsWorld.getBodies();
  4.         while(allMyBodies.hasNext())
  5.         {
  6.              try {
  7.                  final Body myCurrentBody = allMyBodies.next();
  8.                  this.runOnUpdateThread(new Runnable(){
  9.                      @Override
  10.                      public void run() {
  11.                          mPhysicsWorld.destroyBody(myCurrentBody);                
  12.                      }
  13.                  });
  14.             } catch (Exception e) {
  15.                 Debug.d("SPK - THE BODY DOES NOT WANT TO DIE: " + e);
  16.             }
  17.         }
  18.  
  19.         Iterator<Joint> allMyJoints = this.mPhysicsWorld.getJoints();
  20.         while(allMyJoints.hasNext())
  21.         {
  22.              try {
  23.                  final Joint myCurrentJoint = allMyJoints.next();
  24.                  this.runOnUpdateThread(new Runnable(){
  25.                      @Override
  26.                      public void run() {
  27.                          mPhysicsWorld.destroyJoint(myCurrentJoint);                
  28.                      }
  29.                  });
  30.             } catch (Exception e) {
  31.                 Debug.d("SPK - THE JOINT DOES NOT WANT TO DIE: " + e);
  32.             }
  33.         }
  34.  
  35.         if(dSprite.size()>0){
  36.                  this.runOnUpdateThread(new Runnable(){
  37.                      @Override
  38.                      public void run() {
  39.                        for(int i=0; i < dSprite.size(); i++){                  
  40.                              try {
  41.                                  final int myI = i;
  42.                                          mScene.detachChild(dSprite.get(myI));                
  43.                             } catch (Exception e) {
  44.                                 Debug.d("SPK - THE SPRITE DOES NOT WANT TO DIE: " + e);
  45.                             }
  46.                        }
  47.                       }
  48.                 });
  49.         }
  50.         dSprite.clear();
  51.                
  52.         if(dAnimatedSprite.size()>0){
  53.                  this.runOnUpdateThread(new Runnable(){
  54.                      @Override
  55.                      public void run() {
  56.                        for(int i=0; i < dAnimatedSprite.size(); i++){          
  57.                              try {
  58.                                  final int myI = i;
  59.                                          mScene.detachChild(dAnimatedSprite.get(myI));                
  60.                             } catch (Exception e) {
  61.                                 Debug.d("SPK - ANIMATEDSPRITE DOES NOT WANT TO DIE: " + e);
  62.                             }
  63.                        }
  64.                       }
  65.                 });
  66.         }
  67.         dAnimatedSprite.clear();
  68.                
  69.         if(dShape.size()>0){
  70.          this.runOnUpdateThread(new Runnable(){
  71.              @Override
  72.              public void run() {
  73.                for(int i=0; i < dShape.size(); i++){                   
  74.                      try {
  75.                          final int myI = i;
  76.                                  mScene.detachChild(dShape.get(myI));                
  77.                     } catch (Exception e) {
  78.                         Debug.d("SPK - THE SHAPE DOES NOT WANT TO DIE: " + e);
  79.                     }
  80.                }
  81.             }
  82.           });
  83.         }
  84.         dShape.clear();
  85.  
  86. // NOW THAT WE UNLOADED ALL ENTITIES ABOVE, NEXT WE BRIEFLY SHOW THE LOADING SCENE WHILE WE CLEAR ALL OTHER SCENES INCLUDING CLEARING THE MAIN SCENE mScene  
  87.   mEngine.setScene(mSplashScene);
  88.   leftJoystick.back();
  89.   mScene.back();
  90.   System.gc();
  91. // NOTE THAT WE DIDNT DO ANYTHING WITH mPhysicsWorld SINCE WE WILL REUSE IT IN OUR NEXT LEVEL SCENE.  AT THIS POINT WE ARE READY TO LOAD THE NEXT LEVEL OF THE GAME WHICH IS JUST ANOTHER SCENE
  92. }      
  93.  
Parsed in 0.048 seconds, using GeSHi 1.0.8.4
User avatar
RealMayo
 
Posts: 1689
Joined: Sat Sep 03, 2011 9:25 pm
Location: Chicago, IL

Next

Return to GLES1

Who is online

Users browsing this forum: No registered users and 11 guests