Out of Memory

Djembefola

Active Member
Licensed User
At times i get an "Out of memory"-Exception, when i restart my application.

I can start my program and work with it, but when i finish it with the Back Button and then try to restart it, it crashes.

The second attempt to restart it (after the Crash) is always succesful.

The exception happens only on a tablet with 1GB RAM. On devices with smaller screens i never had this problem.

Is there any way to catch an Out of Memory-Exception?
 

Djembefola

Active Member
Licensed User
Seems to happen, when i initialize a Canvas.


B4X:
FATAL EXCEPTION: main
java.lang.OutOfMemoryError
   at android.graphics.Bitmap.nativeCreate(Native Method)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:604)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:584)
   at anywheresoftware.b4a.objects.drawable.CanvasWrapper.Initialize(CanvasWrapper.java:71)
   at diva.dst.main._drawstartscreen(main.java:1705)
 
Upvote 0

Djembefola

Active Member
Licensed User
What device are you using (which resolution)? Can you post your code or at least the relevant parts?


The code ist pretty long and the error seems to happen in different procedures, but it is always related to the Initialization of a global canvas object. When i tested it today, the very first line of my program forced the crash (after a Restart of the Application):

B4X:
Sub Activity_Create(FirstTime As Boolean)
Dim w,h,g As Int

   
   cnv.Initialize(Activity)


The unfiltered Log shows:

B4X:
FATAL EXCEPTION: main
java.lang.OutOfMemoryError
   at android.graphics.Bitmap.nativeCreate(Native Method)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:604)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:584)
   at anywheresoftware.b4a.objects.drawable.CanvasWrapper.Initialize(CanvasWrapper.java:71)
   at diva.dst.main._activity_create(main.java:499)
   ....

The Device, which causes the error is an ACER Iconia A500 Tablet with 1280*800 and 1GB RAM.

I don't have any Problems on other Devices, e.g. Samsung Galaxy II (800*480, 2GB Ram). I assume, the Iconia Tab with 1GB RAM could be a little bit underpowered for a High-Resolution Screen.
 
Upvote 0

Djembefola

Active Member
Licensed User
I have declared a Canvas Object in Sub Globals and use it in different procedures to draw bitmaps. It is initialized several times for different views.

B4X:
Sub Globals
Dim cnv As Canvas               'Activity Canvas
....
End Sub
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
Each time that you initialize the canvas it creates a bitmap with the size of the target view. The first thing that you should make sure it that you are not creating unnecessary bitmaps, especially for the larger views or activity.
For the activity you can create a process global bitmap and then set it as the activity background. You can draw on it with Canvas.Initialize2. This way there will be need to create a new bitmap each time the activity is created.
You can also do it for other large views.
 
Upvote 0

Djembefola

Active Member
Licensed User
Ok,i will try to revise my code. Maybe, i'm using a little bit too often Wallpapers and other odds and ends.
Thank you for your replies.
 
Last edited:
Upvote 0

Silentsea

Member
Licensed User
Hi,

I will post in this thread, because I have a similar problem. My code works pretty good if I run trough my buttons and exit functions etc. I load images by click on a preview and then i initialize the cavas to draw. As mentioned this workes fine and I can do this a hundred times. But when I left this activity in some special ways (Back Key / Standby Click / Standby after time) next time there will be a memory problem. I can't figured it out, because if i resume out of my own functions all works fine. Some ideas? Where is the difference? It's only another resume? Is there a way to destroy old objects at resume? By the way why is a click at the back key resulting in activity pause with userclosed = true a click at standby key with userclosed = false?

Maybe this is in relation to the cam lib from xerv which I use and which has to be loaded at resume.

*00:05:18* before load
*00:05:18* after load
*00:05:18* before Canvas
GC_EXTERNAL_ALLOC freed 4523 objects / 290488 bytes in 36ms
*00:05:19* after Canvas

**first time Works fine**

*00:05:19* Pic loaded
Delivering toWindow{483b36a8 ****.amodulfoto paused=false}
Delivering toWindow{483b36a8 ****.amodulfoto paused=false}
*00:05:20* before load
*00:05:20* after load
*00:05:20* before Canvas
7680000-byte external allocation too large for this process.
VM won't let us allocate 7680000 bytes
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
FATAL EXCEPTION: main
java.lang.OutOfMemoryError: bitmap size exceeds VM budget


My first solution was to disable the back key in my cam modul but there is also the standby key, additionally this isn't a beautiful solution ;). Another approach was to Activity.Finish at activity_pause when pausing comes from system, but first this isn't an expected user experience and second this doesn't work either. There is also the mem leak?

Silentsea
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
It might be the classic "large native allocated bitmap is wrapped by a small managed bitmap wrapper and so the VM garbage collector is not collecting the wrapper because it doesn't think it's out of memory yet while the native heap is exhausted" problem. You could try explicitly freeing up the bitmaps and see if that helps.

My PageTurnView library has a RecycleBitmap function you could use to try freeing a bitmap when you know you don't need it or it's trivial to do it with my Reflection library.
B4X:
Dim Obj1 As Reflector
Obj1.Target = bmp ' bmp is the unwanted Bitmap
Obj1.RunMethod("recycle")

You can get the bitmap from a canvas but note that if the canvas is initialised on a view you will need to give that view another drawable or initialize a canvas on it before it is drawn again or you will get a "Canvas: trying to use a recycled bitmap " exception and your app will force close.
B4X:
Obj1.Target = canv
Obj1.Target = Obj1.GetField("bw")
Obj1.Target = Obj1.RunMethod("getObject")
Obj1.RunMethod("recycle")
 
Upvote 0

Silentsea

Member
Licensed User
Thanks agraham,

it works on my Acer Iconia A 500, but not on my galaxy tab. There I noticed also an other standyby process. At the Iconia (Honeycomb) it will only resume after standby, at the galaxy tab (Froyo 2.2) it will also do the create step (first = false).

Also the mem the system wishes is about 7.600000, it doesn't matter if the canvas size is 20x20 oder 1600x1200.

Currently I do not have any ideas, how to solve my problem.

Silentsea
 
Upvote 0

Silentsea

Member
Licensed User
I've tried to isolate the problem a little bit more. If I do not call camera api (lib by xerv) there is no memory problem. Also there is no problem if I take a lower resolution of the cam. :BangHead: This results now in two questions.

Is there a way to grab the ram of device (or how much is possible for a process)? So I can change the resolution if low memory is available.

Why does this only happen after a new creation, it seems as the activity wouldn't be completly destroyed or something else :confused:?

Some ideas?

Silentsea
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
Each time you call Canvas.Initialize(Activity) a new bitmap is created. Eventually the garbage collector should release the old bitmap. However as this bitmap can be very large you are getting an out of memory problem.
The solution is to create a mutable bitmap and draw on this bitmap (using Canvas.Initialize2). This will allow you to reuse the bitmap even when the activity is destroyed.
You can assign this bitmap as the activity background by creating a BitmapDrawable.
 
Upvote 0

Silentsea

Member
Licensed User
Hi Erel,

may be there is some misunderstanding. I've tested this way:

B4X:
cTools.Debug("before InitializeMutable")
Dim MBitmap As Bitmap
MBitmap.InitializeMutable(Resolution.Width,Resolution.Height)
cvspaint.Initialize2(MBitmap)
   
cTools.Debug("before DrawBitmap")
Dim Rect As Rect
Rect.Initialize(0,0,Resolution.Width,Resolution.Height)
cvspaint.DrawBitmap(picture,Null, Rect)
   
cTools.Debug("before SetBackgroundImage")
pnlImage.SetBackgroundImage(MBitmap)

It takes only slightly longer and the same error occurs. So my main point at the moment is, that the different os versions respond different (resume / restart), and I asked me why? Is this correct?

Silentsea
 
Upvote 0

Silentsea

Member
Licensed User
Yes I noticed and just changed that to Process_Globals, but I want some more tests before I feel happy, than I would have published my answer ;). It looks good, so thanks again Erel. :sign0142:

Silentsea
 
Upvote 0

ondesic

Active Member
Licensed User
Erel,

I am having the same problem. I have 3 panels with 3 canvas. THey are each 1000x1400. I know this is a lot of memory but i find that everything runs fine the first run. THen I close it. On the Second run I get an out of memory error.

I find if I force close the app everytime I DON'T get this problem. Is this a leak (remember it runs fine everyother time)?
 
Upvote 0
Top