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:
User starts the app and goes to mainmenu
User chooses a mainmenu item which sets the GLSurfaceView to View.VISIBLE
User plays with the in-built game on GLSurfaceView
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.
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
Related
in my android project i scan a image and then gets redirected to a new activity. In onPause i release my camera and in onResume i re-create it.
When using my back-button to go back to the camera-view; i get the feeling that it reacts slowly. I know for a fact that this i because the program dont change view before i created new camera instance in onResume.
My question is: How can i make the program show camera-activity view before making the camera instance to make everything "look" faster?
Hope i am clear! :)
refer to Android Camera online document:
Caution: On some devices, this method may take a long time to
complete. It is best to call this method from a worker thread
(possibly using AsyncTask) to avoid blocking the main application UI
thread.
Yes, you can open() camera in a background thread. I am not sure that this is what slows your activity display.
On cocos2d-x's game. When I pressed the home button to quit the game. The next time, how can I make the game must start over again, but not followed by the last exit scene
Ideally in applicationWillEnterForeground you should simply replace the scene with a new instance of it to start over e.g. if the class of scene you were running is called GameLevelScene you should simply tell CCDirector to replace the running scene with a new instance from it's class. For example:
CCDirector::sharedDirector()->replaceScene(GameLevelScene::create());
But while I was doing something similar to pause my game on resuming from background I noticed that it wasn't quite working (it should've, maybe this is some problem with cocos2d-x). So, as a work around, I created a sequence with a delay time of zero at it's start and then called my game's pause function. I guess the game needed to take one tick to process this after resuming from background. For you, if the above doesn't work just try this:
someNode->runAction(
CCSequence::create(CCDelayTime::create(0.0f),
CCCallFuncO::create(CCDirector::sharedDirector(),
callfuncO_selector(CCDirector::replaceScene),
GameLevelScene::create()),
NULL));
someNode can be any node in your game which is living in the game i.e. it hasn't been destroyed; it must be an alive object. You can have a game manager node which is alive at all times during your game. The game manager node can be made responsible for such game management issues.
Right now I'm developing a game in Android (OpenGL ES 1.1) and I'm seeing that whenever I create a new SurfaceView (GLView) its thread is created. That's ok. The problem comes when I want to finish the Activity that holds the SurfaceView (and go back to the menu). It seems that the activities are not released because each GLThread is referencing it. This may finish with an OOM error.
Some MAT pictures:
The first picture: the MarkitActivity represents each single instance of the Activity that deals with SurfaceView.
The second picture: The list of all the activities in memory.
The Third Picture: What is holding the Activities from GC.
If any code is needed I will post it. Nevertheless I have already tried the following things:
->Weak reference of the Activity Context to the renderer and to the surfaceview.
->Application Context instead of Activity Context (in normal and weak mode).
->Trying to stop (in a hard way) the thread (interrupt) and waiting for join (Which the program does it, but the thread does not care, it is still there...)
->Trying without debugging, just in case in debugger mode the values changes (the MAT pictures are without debugger).
->Trying the Activity as singleInstance mode. Weird results and errors everywhere.
->onPause and onResume are correctly controlled for the view.
Any hint, idea, question or help will be really appreciated. Thanks in advance!
Carlos.
I had a similar problem with threads (but not using OpenGL), and end up solving it using a simple trick.
Before exting activity (in onPause() or onStop(), try nulling the thread like this:
myThread = null;
It seems that it makes the Thread GC collectable, and therefore you activity becomes also collectable.
It worked for me, as well as for some people with similar problems to whom I gave the same suggestion.
Regards.
I have a normal Main activity that calls the Game Activity Surface (in Open GL), which loads all the textures so play the game.
If I drop the activity with OpenGl surface, the engine delete the textures and close the activity game. Seems ok, but...
In Main Activity (normal activity), if I call the game activity (repeating load textures) the game drain much memory in heap (seems duplicate) and the frame-rate of the game get slow. If I repeat the process, the memory heap is increasing.
And what happens if I close the entire app? The Android free-up and I could re-open the app in normal speed and memory consume.
I tried garbage ... seems something related to opengl surface.
My question: closing the surface activity that contains Open gl, the open gl buffer still allocated in heap? After closed, open a new activity with open gl will duplicate the open gl size ? In memory seems that its happens, but I could finding out the reason.
I got the solution.
Because a weak reference, Android guarded all context in memory.
My game has a pause in game mainThread and show a Toast Message. The user can left or re-enter in the game. If he left the screen, Android keeps the reference of dead activity in memory, probable with all open gl surface too, only because the Toast message, with dead activity reference still popup after close the last activity. I'm just use getApplicationContext().
try to dispose all the texture in the onDestroy() method. that way all the texture will be destroyed when you exit/finish the activity.
#Override
protected void onDestroy() {
super.onDestroy();
for(Texture t:textures) {
t.dispose();
}
}
note : I don't really know that Android has it own texture class. I used libgdx and there's a dispose method to call. maybe you should find a way to dispose all those garbage. If i recall there's a recycle() method in Bitmap class that do similiar thing.
I have a game using OpenGL. I've built off of the examples, for the most part, having the Main Thread, Renderer Thread (GLSurfaceView.Renderer) and added a GameLogic thread as well. When the game is executed, everything seems to run through perfectly. When back is pressed and onPause() is fired, I'm also firing the GLSurfaceView()'s onPause, but I'm having a "crash" at that point. Here's the MainActivity's onPause:
#Override
protected void onPause() {
Log.d("Main", "Pre- Super onPause");
super.onPause();
Log.d("Main", "Post- Super onPause");
mGSGLView.onPause();
Log.d("Main", "Post- GL onPause");
}
Each log point is reached except the last. In logcat, immediately following the "Post Super onPause" line, I get an Activity pause timeout.
I am not overriding onPause in the GLSurfaceView class... and as far as I know this had been working for me for some time, but recently started occurring when I started getting a completely black screen on the second time I tried to run my game which sits until finally getting an ANR. 95% of my game runs natively. Similar to the San Angeles example, the Renderer calls to onDraw, for instance call a NativeDraw function instead of java. The same is true for the onSurfaceCreated, onSurfaceChanged, and I also call a native GameLogic method in the logic thread (basically all that is called there is a thread sleep and that logic method.)
I hope I've given enough information, please let me know if there is anything else I should be providing.
EDIT - Well... I've actually narrowed down the issue to a native function call where I'm freeing certain pointers that had previously had memory allocated for them with malloc(). My code there looks okay, but if I omit the call, everything works okay, so my free() calls must be corrupting something...
Okay, I'm only answering this myself because the solution was so specific to my own code that no one would have been able to.
If you have memory allocated on the native side, take care not to free it until after you are sure no other code will be trying to access it.