java.lang.OutOfMemoryError

176 views
Skip to first unread message

Steve Marcus

unread,
Oct 13, 2013, 4:07:20 PM10/13/13
to alternate-java-bridg...@googlegroups.com
I am getting the dreaded out of memory error, I have tried everything and I don't know how to fix it.

The error is:

FATAL EXCEPTION: main

java.lang.OutOfMemoryError: (Heap Size=192676KB, Allocated=178248KB)

at android.graphics.Bitmap.nativeCreateScaledBitmap(Native Method)

at android.graphics.Bitmap.createScaledBitmap(Bitmap.java)

at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.CanvasView.scaleDrawBitmap(CanvasView.java:257)

at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.CanvasView.onLayout(CanvasView.java:250)

at android.view.View.layout(View.java)

etc...

I am using about 14 activities, all have background images, two have canvases with image sprites. It errors after several minutes of gameplay after switching activities several times (the app is a game), and always on the screen with the canvas and imageSprites. I am closing activities behind me as I go.

For each activity, in onDestroy I have added the following:

I have tried recycle
((BitmapDrawable)view.getBackground()).getBitmap().recycle();

I have tried to set callbacks to null
view.getBackground().setCallback(null);

I have tried removing views
((ViewGroup) view).removeAllViews();

I have called garbage collector
System.gc();

I have tried to set inPurgeable to true
BitmapFactory.Options opts=new BitmapFactory.Options();
        opts.inDither=false;                    
        opts.inSampleSize = 8;                   
        opts.inPurgeable=true;                 
        opts.inInputShareable=true;             
        opts.inTempStorage=new byte[16 * 1024]; 

But none of these work.

The issue seems to be view.getBackground() appears to be always null.

Any ideas how I can access the canvas background and imageSprite images using BitmapFactory or similar in order to recycle them or set callbacks or set their inPurgeable state to true?

Or any other ideas?


Thanks,


S








Imp Inc

unread,
Oct 14, 2013, 8:06:27 PM10/14/13
to alternate-java-bridg...@googlegroups.com
Hey Steve,

 Looks like the canvas is holding onto the drawing bitmap. You can't really get to that. But, I've added recycle calls to the canvas bitmaps when the activity is destroyed. Grab the new jar, and let me know if it's still happening.

Ryan

Steve Marcus

unread,
Oct 15, 2013, 2:19:41 PM10/15/13
to alternate-java-bridg...@googlegroups.com
Ouch it didn't seem to like that. I've got the new jar (thanks), but now it force closes the app:

looks like it's Canvas.onStop (highlighted below)

10-15 19:15:06.350: E/AndroidRuntime(15327): FATAL EXCEPTION: main
10-15 19:15:06.350: E/AndroidRuntime(15327): java.lang.RuntimeException: Unable to stop activity {appinventor.ai_phantomfoot.myapp/appinventor.ai_phantomfoot.myapp.Screen1}: java.lang.NullPointerException
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.ActivityThread.performStopActivityInner(ActivityThread.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.ActivityThread.handleStopActivity(ActivityThread.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.ActivityThread.access$900(ActivityThread.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.ActivityThread$H.handleMessage(ActivityThread.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.os.Handler.dispatchMessage(Handler.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.os.Looper.loop(Looper.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.ActivityThread.main(ActivityThread.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at java.lang.reflect.Method.invokeNative(Native Method)
10-15 19:15:06.350: E/AndroidRuntime(15327): at java.lang.reflect.Method.invoke(Method.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at dalvik.system.NativeStart.main(Native Method)
10-15 19:15:06.350: E/AndroidRuntime(15327): Caused by: java.lang.NullPointerException
10-15 19:15:06.350: E/AndroidRuntime(15327): at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.Canvas.onStop(Canvas.java:1558)
10-15 19:15:06.350: E/AndroidRuntime(15327): at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.Form.onStop(Form.java:782)
10-15 19:15:06.350: E/AndroidRuntime(15327): at appinventor.ai_phantomfoot.myapp.Screen1.onStop(Screen1.java:1436)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.Instrumentation.callActivityOnStop(Instrumentation.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): at android.app.Activity.performStop(Activity.java)
10-15 19:15:06.350: E/AndroidRuntime(15327): ... 12 more

Imp Inc

unread,
Oct 15, 2013, 6:00:51 PM10/15/13
to alternate-java-bridg...@googlegroups.com
Sorry about that. My bad again. New jar is up.

Steve Marcus

unread,
Oct 16, 2013, 3:54:33 PM10/16/13
to alternate-java-bridg...@googlegroups.com
Thanks for that but I can't get a new jar, it keeps saying This project contains the most up-to-date jar file.

Imp Inc

unread,
Oct 16, 2013, 8:47:33 PM10/16/13
to alternate-java-bridg...@googlegroups.com
Sorry about that. I ran into a conflict right after posting that of course. I'll get it up there in the next day or two.

Imp Inc

unread,
Oct 20, 2013, 12:39:56 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Ok, sorry it took so long, but the new jar is up on the server now.

Steve Marcus

unread,
Oct 20, 2013, 3:09:48 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Thanks so much, got it. 

Well it's a lot better, it takes longer to occur (maybe twice as long) but I'm afraid it still happens.

10-20 19:46:47.183: E/dalvikvm(3993): Out of memory: Heap Size=195616KB, Allocated=180333KB, Limit=196608KB
10-20 19:46:47.183: E/dalvikvm(3993): Extra info: Footprint=195616KB, Allowed Footprint=195616KB, Trimmed=49864KB
10-20 19:46:47.183: E/Bitmap_JNI(3993): Create Bitmap Failed.
10-20 19:46:47.183: E/Bitmap_JNI(3993): Failed to create SkBitmap!
10-20 19:46:47.183: W/dalvikvm(3993): threadid=1: thread exiting with uncaught exception (group=0x41532798)
10-20 19:46:47.193: E/AndroidRuntime(3993): FATAL EXCEPTION: main
10-20 19:46:47.193: E/AndroidRuntime(3993): java.lang.OutOfMemoryError: (Heap Size=195616KB, Allocated=180333KB)
10-20 19:46:47.193: E/AndroidRuntime(3993): at android.graphics.Bitmap.nativeCreateScaledBitmap(Native Method)
10-20 19:46:47.193: E/AndroidRuntime(3993): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java)
10-20 19:46:47.193: E/AndroidRuntime(3993): at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.CanvasView.processSizeChange(CanvasView.java:279)
10-20 19:46:47.193: E/AndroidRuntime(3993): at com.xiledsystems.AlternateJavaBridgelib.components.altbridge.CanvasView.onSizeChanged(CanvasView.java:308)

Anything else you can possibly do? Or something I can do at my end? I am calling gc() but I suspect it is still holding on to the bitmap so it won't make a difference.


Imp Inc

unread,
Oct 20, 2013, 4:03:33 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Hmm, I wonder if it's other bitmaps that are not getting released. When the Canvas activity is destroyed, the Canvas' bitmaps are recycled, so it can't be holding on to them.

Also, try adding

    android:largeHeap="true"

 to your application tag in the AndroidManifest. On devices with API 14 or higher, this will assign a larger heap size. This won't necessarily fix all problems, but it will at least allow the app more heap memory.

Imp Inc

unread,
Oct 20, 2013, 4:05:38 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Also, how many sprites do you have going?

Steve Marcus

unread,
Oct 20, 2013, 4:37:53 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Ok I've added largeHeap to the manifest. Let's see how that goes. but that is only for android 4.0 and up?

I have 7 image sprites on the main canvas. Some change images fairly frequently.  One is as large as the canvas, whose file size is about 80kb.

I also have one canvas which is never destroyed, on the splash screen. It has 1 sprite as large as the canvas, again around 80kb. This activity stays open all the time, until the user closes the app.

At this stage I would be willing to pay for someone to have a look at it to fix it as it is driving me crazy :)

Also, do sounds occupy heap memory as well?



Imp Inc

unread,
Oct 20, 2013, 4:46:24 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Ok, it's probably the fact that the imagesprites are changing images so often.

Everything in your app that uses memory uses heap memory.

For images, to figure out how much memory a bitmap will consume, the formula is width times height times 4. That gives you how many bytes the image will take up (regardless of filesize). So an image that takes up the whole screen at let's say 480x800 would take up 1536000, or 1.5MB of memory.

What I would suggest is to use a spritesheet. Grab TexturePacker, and put all your sprite images into one sprite sheet, then use that to assign your sprite's images.

Steve Marcus

unread,
Oct 20, 2013, 5:09:20 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Ok wow that sounds ominous. I'll try to give it a go. Thanks for all the help.

Regarding the sounds.. now with the new jar, the sounds stop playing after a while, saying no more track names available. Is this related to the Out of Memory error?

I am creating/initializing/loading the sounds for each activity separately, every time each activity starts, even though some activites share the same sounds. Would it be better to have them all public static on one activity and reference them from there? Which would probably mean they would be in memory the whole time even though they are not always used?

10-20 19:44:19.605: E/AudioFlinger(1201): no more track names available
10-20 19:44:19.605: E/AudioTrack(3993): AudioFlinger could not create track, status: -12
10-20 19:44:19.605: E/SoundPool(3993): Error creating AudioTrack
10-20 19:44:19.605: I/Sound(3993): SoundPool.play returned stream id 1
10-20 19:44:20.476: E/AudioTrack(3993): AudioFlinger could not create track, status: -12
10-20 19:44:20.476: E/SoundPool(3993): Error creating AudioTrack
10-20 19:44:20.476: I/Sound(3993): SoundPool.play returned stream id 2
10-20 19:44:21.237: E/MediaPlayer(3993): error (-19, 0)
10-20 19:44:21.247: D/MediaPlayer(3993): Mediaplayer receives message, message type: 200
10-20 19:44:21.247: I/MediaPlayer(3993): Info (1,902)
10-20 19:44:21.247: E/MediaPlayer(3993): Error (-19,0)
10-20 19:44:21.247: E/MediaPlayer(3993): stop called in state 0
10-20 19:44:21.247: E/MediaPlayer(3993): error (-38, 0)
10-20 19:44:21.247: D/MediaPlayer(3993): release() in

Imp Inc

unread,
Oct 20, 2013, 5:11:21 PM10/20/13
to alternate-java-bridg...@googlegroups.com
I should give a little more info here.

Check the wiki for how to create the spritesheet with TexturePacker. Put the resulting sheet into the drawable-nodpi folder (create it if it does not exist).

Each imagesprite should have it's own SpriteSheetHelper (unless it uses the same spritesheet, in which case you could use the same one).

ImageSprite sprite = new ImageSprite(canvas);
SpriteSheetHelper helper = new SpriteSheetHelper(this, R.drawable.sheet1);
helper.loadSheetData("sheet1data.json");
sprite.SetSpriteSheetHelper(helper);

The above will automatically assign the first image in the spritesheet to the imagesprite's image. Each image in the sprite sheet is indexed. They may not be indexed to how you want them listed, so you can use these methods to resort the indexes:

ArrayList<String> fileNames = helper.frameOrder();
// Reorder the list how you want them to appear, then set the new frame order
helper.setFrameOrder(fileNames);

TexturePacker creates a json data file of all the images in the spritesheet, including the original image filenames. These are the names that will appear in the ArrayList above.

Then, to change images in the sprite, (indexing is 0 based)

sprite.gotoFrame(1);

Imp Inc

unread,
Oct 20, 2013, 5:21:22 PM10/20/13
to alternate-java-bridg...@googlegroups.com
Hmm I didn't change anything with the Sound component, so I'm not sure what's going on there.

You may want to think about having a FormService handle your sounds. Check the examples source (BoundServiceExample.java, and MyFormService.java). You can instantiate your sound component in the FormService, and load all sounds when it starts, then have your Forms bind to the service. Then you put methods in your service to play the sounds. From the form, you can call the service methods once you've bound to it.

Steve Marcus

unread,
Oct 21, 2013, 3:29:54 PM10/21/13
to alternate-java-bridg...@googlegroups.com
Ok got it working with the sprite sheet (great program btw), however I don't think it will work for my app - the sprite images do not rotate when I change the sprites heading. Is this not possible with a sprite sheet?




Imp Inc

unread,
Oct 21, 2013, 6:41:35 PM10/21/13
to alternate-java-bridg...@googlegroups.com
Ahh, yeah it's not possible right now. I never got around to implementing that, and probably won't for some time.

Here's what I suggest you do instead.

If you don't have too many images you're using, load each drawable first. Then use that to switch images.

private static Drawable frame1;
private static Drawable frame2;
private static Drawable frame3;
private static Drawable frame4;
private static Drawable frame5;

// in $define

frame1 = getResources().getDrawable(R.drawable.firstFrame);
frame2 = getResources().getDrawable(R.drawable.secondFrame);
frame3 = getResources().getDrawable(R.drawable.thirdFrame);
frame4 = getResources().getDrawable(R.drawable.fourthFrame);
frame5 = getResources().getDrawable(R.drawable.fifthFrame);

// Then, when you need to swap images, you use one of the above
sprite.Picture(frame2);
sprite4.Picture(frame1);

This way the drawables get loaded into memory once (instead of constantly being loaded, then dropped). The problem is usually when switching images quickly, the gc doesn't catch up in time, and an OOM occurs.

I uploaded a new jar to the server with the new method in ImageSprite which will allow setting the Drawable like above.

Steve Marcus

unread,
Oct 22, 2013, 10:27:31 AM10/22/13
to alternate-java-bridg...@googlegroups.com
Great, that worked, thanks!

Steve Marcus

unread,
Oct 29, 2013, 10:05:24 AM10/29/13
to alternate-java-bridg...@googlegroups.com
Hooray found one of the problems.. threadTimers. I did not set AutoToggle to true, and so it was still holding onto the reference for the activity after it was destroyed.

But there is still another issue which is causing OOM.. memory analyzer shows one activity (which has a canvas) has many recurring references to java.lang.ref.FinalizerReference, and also a few references to Sound component and Player component. 

I have 3 Sound components and 1 Player component public static on a single activity (my splash screen), and I call the sounds from other activities. 

Is there any way these might be the cause of the activity not being released properly?


Imp Inc

unread,
Oct 29, 2013, 11:27:14 AM10/29/13
to alternate-java-bridg...@googlegroups.com
Yeah, that could be it. Activities aren't meant to be used like that. I've been under the weather lately, but I do have your test service project, and will get to it as soon as I can.

Steve Marcus

unread,
Oct 31, 2013, 4:51:20 PM10/31/13
to alternate-java-bridg...@googlegroups.com
Well in actual fact it turns out it was the thread Timers all along - even with AutoToggle set to true I still got the OOM error.

So as a test I changed them to Clocks, and bingo! No more OOM error and force closes at all.

I can see the heap is still growing, very slowly, but it is so slowly it would probably take continous 10 hours of gameplay to OOM the app.

So I am happy with that for now. Thanks Ryan for all your help and support! as ever. Hope you get well soon.


Steve

Imp Inc

unread,
Nov 1, 2013, 11:56:17 AM11/1/13
to alternate-java-bridg...@googlegroups.com
Interesting. How many did you have going?

Steve Marcus

unread,
Nov 2, 2013, 8:24:36 AM11/2/13
to alternate-java-bridg...@googlegroups.com
I had two of them
Reply all
Reply to author
Forward
0 new messages