Android 1.6 loading bitmap woes - Resolved

stevel05

Expert
Licensed User
Longtime User
Firstly I apologize for the size of this post in advance but some may find it useful. It's doesn't really meet the criteria for a stack overflow question so I thought I'd post it here.

I have just spent the last two days hunting down a problem that appeared when using Android 1.6 on the emulator (I don't have a real device to try it on).

I have been writing a menu system that uses bitmaps as a template and adds text for options, there can be any number of options so potentially loads of Bitmaps, so I decided to create each bitmap, only when necessary and store it to DirExternal.

I needed three bitmaps stored internally, the template, the current menu as I wanted to be able to scroll it by drawing it in various places across a canvas and the one that actually resides in the panel that the canvas is attached to.

The total size of these 3 bitmaps is about 2.4Mb.

This worked perfectly on all but Android 1.6 which gave an out of memory loading bitmap error consistently after loading the 4th menu. Which I thought was strange as it obviously could cope with holding the 3 bitmaps at once.

For this menu I have implemented a complex map which holds views and other maps so I thought memory leaks may be a possibility if I'd done it incorrectly, I searched the internet and found an excellent guide on StackOverflow here, but it turned up nothing.

I then looked at the memory heap that was available in the DDMS (mentioned in the SO post). The only thing that seemed strange was that in 1.6 the garbage collection didn't appear to happen as often.

I found a call on Android Developers site to System.gc that suggest to the OS that now would be a good time to run garbage collection. Implemented that via reflection after loading a bitmap and hey presto, the problem seems to have dissappeared!

I really didn't want to give up on Android 1.6 as there must be loads of users that still have that.

I've posted this for two reasons, first it may help someone else if you get into the same situation and second, someone with more knowledge of Android may say this is the wrong approach and provide a better solution.
 

agraham

Expert
Licensed User
Longtime User
Bitmaps handling on devices with limited memory was a problem in Windows Mobile under C# and is a problem in Android under Java. The reason is that the actual bitmap is a large native object but the managed code garbage collector doesn't know that.

Running a garbage collection is a brute force way of dealing with the problem but it is more efficient to release the native resource. See my post
http://www.b4x.com/forum/basic4android-updates-questions/10760-out-memory-2.html#post62144
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Hi Andrew,

Thanks for the reply, the problem I have is that I haven't finished with either of the bitmap resources I am replacing them.

This code is called whenever a menu page is turned and is reusable:
B4X:
'Load menu bmp into ThisMenu.CurrentBm as we need it for scrolling the image later
ThisMenu.CurrentBm.Initialize3(LoadBitmap(ThisMenu.MenuDir,FileName))
ThisMenu.MenuCanvas.DrawBitmap(ThisMenu.CurrentBm,Null,ThisMenu.ImageRect)

ThisMenu.CurrentBm is a global variable within a type that holds the current Bitmap and the second is stored on a panel accessed by the canvas that I need to carry on using.

Would I be right in thinking that by assigning a new bitmap to an existing variable or panel background, it would actually do something similar to recycle and make the now redundant space used by the old bitmap available for garbage collection?

In which case, if the garbage collection doesn't run at the appropriate time, it could still run out of memory.
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
Would I be right in thinking that by assigning a new bitmap to an existing variable or panel background, it would actually do something similar to recycle and make the now redundant space used by the old bitmap available for garbage collection?
No, it doesn't recycle the native bitmap, but as long as no other references exist to the managed bitmap object it does make that managed bitmap object available for garbage collection. When the garbage collector runs the managed bitmap object will recycle the native bitmap as it is destroyed. The problem is that native bitmaps are large but the garbage collector knows nothing about that and will not necessarily run because it is only looking at managed objects so you can unknowingly run out of unmanaged memory.

By explicitly calling recycle on a bitmap you are freeing the native bitmap and leaving the managed bitmap to be dealt with by the garbage collector. This is more efficient than invoking unnecessary garbage collections which are expensive to run.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Thanks Andrew, I didn't know the difference between a native bitmap and a managed one, just checked it out. Now I understand. I just have to work out how to implement it.
 
Upvote 0
Top