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)
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.
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
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.
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?
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.
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.
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 ?
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.
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?
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:
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)?