Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.gc() causing slowdown from the second start of Activity

I am experiencing a very strange phenomenon (test device: HTC Desire HD, Android 2.3.5). I know that System.gc() is needless and discouraged, and I don't try to suggest otherwise, but the point is that it shouldn't cause issues either (i.e. it should be useless at most).

I have an application which contains a GLSurfaceView in its view hierarchy. The GLSurfaceView is instantiated and added in the Activity.onCreate(). Normally, the application works like this:

  1. User starts the app and goes to mainmenu
  2. User chooses a mainmenu item which sets the GLSurfaceView to View.VISIBLE
  3. User plays with the in-built game on GLSurfaceView
  4. User goes to mainmenu and exits the activity (=> Activity.finish() is called)

My Activity.onPause() looks like this:

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread

So far so good, everything works fine. However, issues appear after I add the following code to onPause() (for the case when the user exits the game from the mainmenu):

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread    
if (isFinishing()) {
    System.gc();
}

In details: if the Activity is started for the first time (= i.e. the app process didn't exist before), everything works fine. However, starting from the 2nd start of the activity (= after the first exit from the mainmenu, i.e. after the first Activity.finish()), the framerate of GLSurfaceView is reduced by 40-50%, the in-built game becomes slow.

If I remove the System.gc() call, the problem disappears. Moreover, if I do the following, it also gets rid of the problem:

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread
if (isFinishing()) {
    // 1. get layout root of View hierarchy

    // 2. recursively remove (detach) all Views

    // 3. call GC
    System.gc();
}

I didn't add concrete code because it's complex, so I used comments. If I just detach the GLSurfaceView via removeView(), it is not enough. The entire view hierarchy needs to be cleared.

Note that I couldn't find any memory leaks (no Activity leak via drawables/statics etc.). Moreover, of course, the gameThread properly exits when the app is closed (I just didn't include its source code).

Any ideas, guesses? Apparently, System.gc() seems to cause some issues for the Activity/layout destroying mechanism of Android. Again, as I said, if I remove System.gc(), the problem disappears.

like image 462
Thomas Calc Avatar asked Jul 22 '12 16:07

Thomas Calc


Video Answer


1 Answers

I have experience of Android Game Programming. I used to clear all the view in hierarchy because when running threads if you call System.gc() sometimes it happens that your thread has a reference to some of your view, even if you call system.gc() this view won't get removed and if you keep playing again and again this game you will notice that your heap memory is started growing.

It depends upon the memory leak, if you are leaking some KB memory it will take more time to crash your game. The best way it to use Eclipse Memory Anlyser (Eclipse MAT) and compare your stacks.

Step1: take memory snap shot when you start your game for first time Step2: take memory snap shot when you start your game second time Step3: Now compare your both stacks of snapshots it will tell you the difference.

It is a very useful tool. I was having huge memory issues in my game Apache Attack. I fixed them using this awesome tool. Follow this ECLIPSE MAT TUTORIAL

like image 170
AZ_ Avatar answered Nov 16 '22 03:11

AZ_