Too many bitmaps causing an out of memory error!

Mickster

Active Member
Licensed User
Longtime User
Hey guys,

So I've developed an app with 5 different activity modules representing 5 different 'pages'. The app uses a ton of .png images for graphics and I have hit an 'out of memory' error. I've found a few posts discussing this error on the forum, but so far I haven't figured out how I can free up the memory.

The application doesn't need all the images loaded at the same time, so I've been looking for a way to remove them from memory when the user jumps between pages.

To apply the graphics, I've been using the .setbackgroundimage(loadbitmap... routine.

Any ideas? Am I using an inefficient command for loading images? Is there a way to remove them from memory without destroying the objects they're attached to (I need to preserve the objects)?

Thanks.
 

Mickster

Active Member
Licensed User
Longtime User
Thanks for the quick reply, Erel!

I read into the bitmap samples when researching this problem, but I'm not sure they're what I'm looking for. These graphics are being tailored specifically for the program, meaning their dimensions are correct. Are they still useful?
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
The images are just used for graphics. If I create a button, I make the image in photoshop and setbackgroundimage. I'm using a lot of activity sized images for background graphics on each page. These graphics are actually the most important.

How do you remove all references to the images?
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
I was concerned this would be the solution. Currently I'm not declaring bitmaps, I'm using '...loadbitmap(File....' as I thought it was a solution in itself to the memory issue.

To make sure I understand correctly, are you saying I could declare a bitmap for, say, the activity, and whenever a new activity is launched, I'd re-initialize this bitmap but with a different file?

I'm not entirely sure this would work in this circumstance, though.
If I 'Dim Background as bitmap' and then set the background image of multiple activities to 'Background', is that still only one bitmap loaded in memory, or does it create a new bitmap every time?
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
I was concerned this would be the solution. Currently I'm not declaring bitmaps, I'm using '...loadbitmap(File....' as I thought it was a solution in itself to the memory issue.
That is fine. You just need to remove the reference to that.
What code are you using for that?

To make sure I understand correctly, are you saying I could declare a bitmap for, say, the activity, and whenever a new activity is launched, I'd re-initialize this bitmap but with a different file?
Yes, you could do it that way. Or you could destroy the bitmap before leaving the activity, and initialise a new one on the other activity.

I'm not entirely sure this would work in this circumstance, though.
If I 'Dim Background as bitmap' and then set the background image of multiple activities to 'Background', is that still only one bitmap loaded in memory, or does it create a new bitmap every time?
That is only one bitmap created in memory. The actual variable 'Background' only contains a pointer to the bitmap.

Since you have multiple activities, Android can remove an activity if it is running out of memory. So I think you are loading all images in the same activity.
I suggest you upload you code if you can, it would be easier to see what is going wrong.
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
That is fine. You just need to remove the reference to that.
What code are you using for that?

This is the general format of code I have been using when adding all my images.
B4X:
   StaticPanel.Initialize("StaticPanel")
   Activity.AddView(StaticPanel, StaticPanelPosition, 0, StaticPanelWidth, Activity.Height - 40dip)
   StaticPanel.SetBackgroundImage(LoadBitmap(File.DirAssets, "Phenix_Background_1280x768.png"))

Or you could destroy the bitmap before leaving the activity, and initialise a new one on the other activity.

How would you go about destroying the bitmap? Also, don't bitmaps belong in the globals? Meaning that they can't be accessed from different modules. If you can't access the same bitmap, how do you change its attached file?

The project is too large to upload to the site, unfortunately. I've copied the code from the 'main' module into paste bin, if you'd care to take a look.

Code - Pastebin.com

Thanks
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
B4X:
   StaticPanel.Initialize("StaticPanel")
   Activity.AddView(StaticPanel, StaticPanelPosition, 0, StaticPanelWidth, Activity.Height - 40dip)
   StaticPanel.SetBackgroundImage(LoadBitmap(File.DirAssets, "Phenix_Background_1280x768.png"))
I have not tried this but if you do:
B4X:
StaticPanel.SetBackgroundImage(null)
You should be able to remove the only reference to that bitmap, and it should be freed.

How would you go about destroying the bitmap? Also, don't bitmaps belong in the globals? Meaning that they can't be accessed from different modules. If you can't access the same bitmap, how do you change its attached file?
Thanks
Maybe Erel can comment on this. I think you can use bitmaps in globals but it depends on how you use them.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Not sure how this is related to your issue. However bitmaps can be declare as local variables, global variables or process global variables.

B4X:
StaticPanel.SetBackgroundImage(LoadBitmap(File.DirAssets, "Phenix_Background_1280x768.png"))
Unless the above bitmap contains any drawn text you can probably reduce its size to about a quarter and still have a good quality image.
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
Thanks for your help guys, I've been able to rid myself of the OOM error using 'setbackgroundimage(null)'.

However, reloading the images whenever the user switches a page has caused the speed to hit the floor. This is a fairly intensive application, but these tablets should be able to handle this stuff with no problem. It occurred to me that the product I'm making is designed to be a stand-alone application. The target device in question isn't going to need to reserve the device's remaining memory for the sake of other applications. With this is mind, do you guys know of a way I can rid of the Android memory cap? There is no need for my app to be restricted to 16-24mb, and there is 1gb to use with this thing.

Thanks.
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
Hmm, well do you have any idea why I might be experience a lag when loading these images? The device is powerful and should be able to load these things instantly. What's the difference between loading a few images and playing a video?
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
Hmm, well do you have any idea why I might be experience a lag when loading these images? The device is powerful and should be able to load these things instantly. What's the difference between loading a few images and playing a video?
Glad you asked. Video decode is a completely different beast. Every device nowadays has a dedicated video decoder/encoder hardware embedded in the SoC. These are highly optimised pieces of hardware that have driver support and direct access to peripherals that the OS does not provide otherwise. Ofcourse each manufacturer has the option to build it in the way they want. A video decoder will have the bitstream loaded into memory, and the driver will make sure that there is always enough data available by prefetching. The output is written directly to the framebuffer.

I think the bottleneck here is loading the image from the storage card. (I guess PNG transcodes to BMP quite quickly). Since your 1280x768 image is about 4MB, you can maybe have 2 bitmaps in memory, and prefetch the next one while displaying the first one.
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
Thanks for all the help guys!

Clearing up the ram caused my app to run slow, but I realised that I don't have to clear the ram for every single page. I'm splitting the app into two section so it's fast for the most part.

:sign0060:
 
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
Hey guys, I'm back with more memory issues!

I just added the camera to my app and am having trouble getting the captured photo to load without sucking up tons of memory. I'm not talking about the size of the image, I'm talking about Android not releasing the image from memory when I load a new one.

I understand how you're supposed to handle the bitmaps in android, but I can't understand why my code isn't ditching them every time I take a new picture.

This is the code I'm using the assign an image every time the picture taken routine is run.

B4X:
Dim capturedimage As Bitmap
capturedimage.InitializeSample(File.DirRootExternal, "1.jpg", pnlCamera.Width, pnlCamera.Height)
pnlCameraImage.Visible = True
pnlCameraImage.BringToFront
pnlCameraImage.SetBackgroundImage(capturedimage)

Could you guys tell me what I'm doing wrong? My user needs to be able to take and discard as many photos as they desire.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Upvote 0

Mickster

Active Member
Licensed User
Longtime User
Thanks for the links.

When they say that the memory may not cleared immediately, do they mean immediately for a computer or for a human? :D

If it's supposed to take a few minutes then that would explain what I can see in the logs, if not then I'm not sure 'recycle' is working...unless of course it's working and the effects aren't seen in the log. Any ideas?
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
The exact truth about Bitmaps and memory release seems impossible to to know!
Lots of learned people have conflicting views.

I'd tend to believe post #80:

The exact steps in dalvik to collect a bitmap is as follows:

1) A bitmap becomes eligible for garbage collection
2) The GC eventually runs and sees that the object requires finalization
3) The bitmap is placed onto the finalizer queue
4) The finalizer eventually runs and native memory is freed (at this point, most of the memory you assigned to the bitmap is freed)
5) The GC eventually runs again and the bitmap is removed from the Dalvik heap. This "remainder" object is relatively small when compared to the previously in-use native memory

Which all sounds very authoritive and knowledgeable.

The key problem though is not the process of freeing memory but the very vague timescale it can take for memory to be freed.

Memory used by a Bitmap is not fully freed until the garbage collector has run at least twice.

Calling a Bitmap's recycle() method sooner rather than later makes it more likely that the memory release process will start sooner rather than later.
Once the recycle() method has been called that Bitmap is marked as a candidate for destruction.

You cannot force the garbage collector to run - you can only request that is run.

So with no control over when the garbage collection takes place you have no control over when the memory will be fully freed.

Martin.
 
Upvote 0
Top