I am using a BitmapFont as follows:
create(){
font = new BitmapFont(getFileResource("50.fnt"), getFileResource("50.png"),
false);
}
dispose(){
font.dispose();
}
I have several screens that load and unload fonts of different sizes. As time goes by, the memory fills up.
After spending a long time looking for a memory leak, I find this BitmapFont class is leaking. I think it is leaking on native memory because the leak is not seen using Memory Analyzer.
I am following the procedure to clean up the memory according to the current documentation. But this is not enough. What else should I do to ensure the BitmapFont lets go of its memory ?
This might be a bug. Here you can see your constructor. And here a very similar one. The difference is that the 2nd sets the ownsTexture flag. Only if this flag is set, the texture gets disposed.
I will create an issue/PR to fix this problem or at least make it behave the same way, or add a JavaDoc warning.
For now you can solve this problem by doing bitmapFont.setOwnsTexture(true) yourself.
The error was that the libgdx code is long running, so I could not wait for dispose to be called.
So I was calling dispose on the elements that were no longer needed on the screen from a thread other than the GLThread (on Android)
Libgdx ignores dispose() when not coming from the GLThread().
Adding the clean up code on render such that it runs when outdated components pile up fixed the problem.
Related
My app uses a service which I start in the main activity's onCreate() method. When I first launch the app on my tablet, and view what's running in Settings/Apps/Running, it shows my service running and consuming 11MB of RAM.
Now, if I cycle the activity's life cycle 20 times by rotating the device, and go back into Settings/Apps/Running, it shows that I'm now using 29MB of RAM.
At first I thought this must be due to a memory leaks, but after taking heap dumps before and after cycling the activity's life cycle, I don't appear to be leaking any objects. Below is a screenshot from MAT, where the column titled Objects #0 lists instances of my objects before cycling, and column titled Objects #1 lists instances of my objects after cycling.
and for all objects
There don't appear to be any obvious memory leaks, and yet I can't understand why the RAM usage in Settings/Apps/Running increases after each orientation/lifecycle. Am I missing something here? Why is my RAM usage apparently increasing, when I don't appear to have any memory leaks?
Update
The reason my app was consuming more RAM on each orientation change was the result of creating custom fonts from assets. I had created a custom TypefacedTextView (can be seen as an object in the screenshots above) that appears to have been reloading the fonts into memory each time the view was created. Removing the TypefacedTextViews has fixed the problem. The problem was made clearly apparent using the adb tool with command shell dumpsys meminfo my.package.com which listed my abundant font Asset Allocations.
There's a short blog post which, I believe, holds a lot of information nonetheless. You can find it here.
In it you find an intereseting explanation of what can/will happen if you manage your Activity's references wrongly:
private static Drawable sBackground;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
This code is very fast and also very wrong; it leaks the first
activity created upon the first screen orientation change. When a
Drawable is attached to a view, the view is set as a callback on the
drawable. In the code snippet above, this means the drawable has a
reference to the TextView which itself has a reference to the activity
(the Context) which in turns has references to pretty much anything
(depending on your code.)
Since you're talking about memory leaks on orientation changes, you may very well be making the mistakes the author details in his post.
Hi Android Developers,
What is the best way to interrupt a current rendering phase of GLSurfaceView and start a new one when mode is equal to "Render_when_dirty"? I artificially stop rendering in "onDraw" method by checking a flag and returning from actual rendering method which is called in "onDraw" method; then, in main thread's context i call "requestRender()" to refresh the scene. However, due to a reason that i am not aware of, some of the intermediary old frames are displayed for a very very short period of time(on the other hand, they endure for so long period of time that users can realize the transition); before actual scene is rendered by opengl es 2.x engine. It doesn't affect anything at all; but troublesome to be fixed. What do you suggest?
P.S. Throwing InterruptedException within onDraw method is useless due to the destruction of actual rendering thread of GLSurfaveView.
Kind Regards.
When you say some of the old frames are drawn - do you mean part of the frame that is drawn is old or multiple calls of onDraw() still lead to some of the old information being shown on the display.
There are a few things I can see happening here. If you have a onDraw() like this:
onDrawFrame(){
... stuff ...
if (stateVariableSet)
return;
... stuff ...
my understanding is that when the function is done being run, that the back/front buffer get swapped and drawn. One thing that could be happening here is that you see a few calls of onDrawFrame() being rendered while you try to update the state/State variable.
On the other hand, if you have something like this:
onDrawFrame(){
... stuff..
semaphore.acquire(); // lock the thread waiting for the state to update
... stuff ...
then the things that have been drawn before the lock will be stale (for that frame only though - at least that's what I'd anticipate).
Also are you running on a multi-core system?
I have simple android app. App includes around 50 images, mostly PNG format, but also most of them are icon size. There is about 5 layouts and use Google maps and WebView. App itself weights bit under 6MB.
Then i run all of app options and then i look into app settings -> cached processes, i see my app uses 70 MB of RAM !!!
Im calling finish() method wherea i can, but that doesnt help. What could help to reduce memory use ?
Even Angry birds is using less !
It might be that you're loading your Bitmaps with methods that create immutable Bitmaps and not releasing them adequately (you have to take care to dispose of all of their references or else the garbage collector will never free the space they're using.
If that's the case, this reference might help you with the Bitmaps you're using.
The best way is to use 9 patch PNG images for your application. This will definitely help you to reduce cache size as well as application size. More over deploy you application code according to android life cycle, excessive use of finish() make the activity to onpause() state, so use onDestroy() where you want to kill that activity.
Create a drawable folder and put all those 9 patch image there.Deploy onDestroy() to fill the activity
Please compress each and every image without affect image quality and then take care of leaked memory. Each activity action completed then finish that activity. once you exit from application. destroy all running methods. if you need to clear memory manually, by calling the .recycle() method of your bitmap object.I think its help you to reduce memory.
Try something like this, it may help i guess:
#Override
protected void onDestroy() {
super.onDestroy();
unbindDrawables(findViewById(R.id.LayoutId));
System.gc();
}
I am developing a game in Android using AndEngine GLES-2. I am facing a problem while resetting a scene after player has completed a level. When I reset the scene, all the sprites lose their positions and tend to appear in each other's positions i.e. they swap their positions.
I have tried all the things like setting all the sprites etc. to null and calling methods like clearUpdateHandlers() and clearEventModifiers() etc. but no success yet.
I found out after a lot of googling that engineOptions.getRenderOptions().disableExtensionVertexBufferObjects(); method can fix this problem. So I am trying to invoke it but compiler gives error saying that this method in not defined for RenderOptions class.
I checked the RenderOptions class in org.andengine.engine.options package and the method really does not exist in that class. Am I missing any plug-in or is there any other problem? Please help, I am stuck.
you need to manually restart the scene, for example:
To restart a Scene you can Finish the activity and Start again but different level with SharedPreferences, or Tag's in intents, or you can set position of each Sprite and cler the Scene with:
//detachChild this Sprites that you do not use
Scene.detachChild(SpriteX);
//clear the space of memory of each sprite that you do not use
SpriteX.dispose();
//unload the bitmaps that you do not use
BitMapsX.unload();
this method have a seconds to run, but you can use a elegant "hud" in you game, and while charging set in the hud a logo or animation with "loading", best regards
Things were going well until I switched off the screen lock on my device, then things started going wrong intermittently.
I've managed to track the issue down and have some workarounds in mind BUT I would like to know if there is 'best practice' for avoiding or removing the issue.
The issue:
I have an application which changes images based on the application status.
The images are not huge but quite large (231k~) and are stored as resources.
After several screen rotations (I counted 27 with a project using a single ImageView), loading the images fails with Exception of type 'Java.Lang.OutOfMemoryError'
Stripped down to the barest project, the following demonstrates the problem:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
//get a reference to the ImageView
var imageView = FindViewById<ImageView>(Resource.Id.imageView1);
imageView.SetImageBitmap( Android.Graphics.BitmapFactory.DecodeResource( this.Resources, Resource.Drawable.Ready) );
}
The above code is the only method I used to reproduce the issue.
Whilst attempting to resolve, I extended the example so that imageView was released in OnDestry:
protected override void OnDestroy ()
{
base.OnDestroy ();
imageView.SetImageBitmap( null );
imageView.DestroyDrawingCache();
imageView.Dispose();
}
This made no difference unless I added GC.Collect() which I don't want to do.
The best workaround I've currently thought of so far would be to modify the code as follows:
static Bitmap _ready = null;
private Bitmap GetReadyImage {
get {
if (_ready == null) {
_ready = Android.Graphics.BitmapFactory.DecodeResource (this.Resources, Resource.Drawable.Ready);
}
return _ready;
}
}
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
//get a reference to the ImageView
imageView = FindViewById<ImageView>(Resource.Id.imageView1);
imageView.SetImageBitmap( GetReadyImage );
}
This relies upon a static reference to each Bitmap and a property accessor for each.
I could even write a method which stores the images in a static List to save writing property accessors for each different property/variable.
I could perhaps add the flags ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize |ConfigChanges.KeyboardHidden) but this would break the normal Activity lifecycle which I've read isn't best practice?
I find it strange that having scoured the web, I've not yest encountered similar issues or examples. I'm left wondering how most others deal with this?
Any thoughts or comments are much appreciated.
I can only approach this problem from a truly native perspective, as I have not worked directly with the Mono framework.
The described symptoms are 100% indicative of a memory leak in the Activity, but the code shows no real evidence. If you can truly produce the issue with a project containing only one Activity and those four lines of code, it sounds to me like it is perhaps a framework bug that ought to be filed with Xamarin. Have you attempted to create the same simple project in pure Java to see how the results fare on the same device/emulator you are using? It would also be interesting to know if the issue is localized to a specific version of Android. I have never seen this particular behavior before in a native application project.
The awkward part is your statement that forcing a garbage collection makes the problem go away. You're right, you shouldn't have to do that, but a true memory leak (i.e. an unreleased reference) would still persist even if you hit the GC several times. The Android paradigm of destroying and re-creating the Activity on each rotation is such that even if the old Activity lived for awhile, when memory was tight it (and all its references) would quickly be collected to make room for a new instance. If this is not happening, and each Activity is living on past even the system triggered GC passes, perhaps there is a stuck reference in the native code generated by Mono.
Interestingly enough, technically your workaround actually does introduce a true leak, by attaching the Bitmap to a static field that is never cleared. However, I agree that in comparison it seems like a more efficient move. A simpler workaround might also be to code your Activity to manually handle configuration changes (I don't know if Mono is different, but this is accomplished by adding android:configChanges="orientation" to the manifest file). This will keep your Activity from being recreated on each rotation, but it may also require you to reload your view hierarchy if you have different layouts for landscape and portrait. However, even if you have to do this the Acitivity instance will be the same you can safely save the Bitmap without resorting to a static field.
However, if you cannot reproduce the problem with the same project in a native Java project, I would report a Mono bug.
Hard to see without the entire code but it obviously sounds like you have a memory leak. Screen rotation (due to the destroying/creation of the activity) is known to cause these. You might want to have a read at this article by Romain Guy as well as this talk from last year's IO.