Forced Close on second start of app

COBRASoft

Active Member
Licensed User
Longtime User
Hi,

Can somebody help me out here? When I start my app the second time, I get a forced close :(. I've included the log, hopefully it will help...

B4X:
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=q2c.m4a/.main bnds=[120,526][240,676] } from pid 423


** Activity (main) Create, isFirst = false **


GC_CONCURRENT freed 1119K, 54% free 3662K/7943K, external 23165K/23907K, paused 2ms+2ms


GC_EXTERNAL_ALLOC freed 24K, 55% free 3643K/7943K, external 24231K/26279K, paused 24ms


1168128-byte external allocation too large for this process.
VM won't let us allocate 1168128 bytes


GC_FOR_MALLOC freed <1K, 55% free 3642K/7943K, external 24231K/26279K, paused 16ms
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x2aac8578)


FATAL EXCEPTION: main
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    at android.graphics.Bitmap.nativeCreate(Native Method)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
    at anywheresoftware.b4a.objects.drawable.CanvasWrapper.Initialize(CanvasWrapper.java:71)
    at q2c.m4a.main._createstep_street(main.java:2847)
    at q2c.m4a.main._activity_create(main.java:377)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:113)
    at q2c.m4a.main.afterFirstLayout(main.java:84)
    at q2c.m4a.main.access$100(main.java:16)
    at q2c.m4a.main$WaitForLayout.run(main.java:72)
    at android.os.Handler.handleCallback(Handler.java:587)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3701)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
    at dalvik.system.NativeStart.main(Native Method)
  Force finishing activity q2c.m4a/.main
Activity pause timeout for HistoryRecord{2afcd748 q2c.m4a/.main}

Greetings,
Sigurd
 

COBRASoft

Active Member
Licensed User
Longtime User
You are running out of memory. Is this a real device or an AVD? How long do you wait before reloading the program. Seems the OS has not yet freed the resources from the first run. What happens if you run your app and then close it, then wait 10mins or so before you try to run it the second time?

Real device (SE Xperia Arc S). Haven't tried the 10 minutes wait yet, but in real use, the customer won't wait 10 minutes, it has to start immediately.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
Another possible solution is to create a mutable bitmap (when FirstTime = True) and set it as the activity background. The bitmap should be a process global variable.
This will allow you to reuse the same bitmap.

I don't quite follow you here. I have only 1 background and I changed my code to LoadBitmapSample and only at Activity_Create time. The crash still happens.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
Ok, I'm a bit further. The background has nothing to do with it actually (I removed it). It's more about the amount of views I place in 1 activity at the same time. I use something like sliding panels, most of them containing a scrollview and all bunch of views in them. This is all initialized and placed by code (with anims and everything). When I remove any of my panels, the error goes away.
So, I really need a working solution for this problem... Any1?
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
I can't publish code due to MDA's :(. That's the biggest problem.

In that specific routine, I just place about 5 simple views on a panel. Nothing else. Perhaps it has to do with all the animation objects I create in global. I'll try turning those all off and look what happens.
 
Upvote 0

margret

Well-Known Member
Licensed User
Longtime User
The 10 mins wait was just to help diagnose if the OS would free up resources. Not that any customer would wait. It would just seem if it ran the first time and the system was giving enough time to clear resources, it should run again and if it does run after the wait period, to find what item was consuming those resources. But sounds like you are past that now.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
Well, not completely past it. It really has to do with freeing resources. I'm converting my complete app to only create the panel that has to be shown and all the rest gets removed of the 'previous' panel. The panel itself is also being removed from the activity. I also removed all the animation just to be sure. I use LoadBitmapSample everywhere and lowered most resolutions of the pngs used for the buttons. So far so good, now I can restart my app 4 or 5 times before I get the crash. Sadly, I still get a crash :(.

Does Java (B4A) has an equivalent to .Nets 'GC.Collect'? This forces the system to free the resources immediately.

P.S.: My app needs to work with Bluetooth, GPS, AdvancedCamera, ... all at the same time during a whole day :).
 
Upvote 0

margret

Well-Known Member
Licensed User
Longtime User
My understanding is that it is handled by the OS. However, with certain graphics, etc. there are ways to clear the stack. Without seeing your code I don't know if this applies but as Erel said:

"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."

This may help to reduce memory requirements.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
I would like to try that, but I removed all drawing for the moment, so this can't be the case. I only have some simple views left. Something else is eating my (external) memory, and I have no idea what (GPS, HttpUtils, BluetoothAdmin, Serial, AdvancedCamera, ...?) :(.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
I'm combining all kinds of tricks and tips. For the moment I have an external memory of 6MB instead of 17MB. I'm redesigning my app completely to use a shared canvas, a shared bitmap and even a shared panel. I clear the panel each time and refill it with the needed views for a specific task. It's becoming quite a complex UI code, but I've done worse on my Amiga 20 years ago :).

Thx for all the help and pointers!
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
HttpUtils PostBytes

Does anyone know when PostBytes will be released in the HttpUtils service?
It is declared in Process_Globals and only assigned in the PostBytes subroutine of HttpUtils.

...so just starting a train of thought here...correct me wherever i go wrong...
If you Post a rather 'large' string using PostString, the string is transfered ByRef, but then PostString calls PostBytes, in which a primitive 'Bytes' is sent, which is sent by Val.
After being assigned in the Sub PostBytes, the variable PostBytes is never cleared/re-assigned until the next call.
Therefore, if you have a large file/string you want to transfer, even after transfering you will have that memory occupied there, until you call PostBytes again.
Also, during the POST, there will be a time when twice the memory is allocated due to the conversion from String to Bytes, there will be 2 copies of the data.

One workaround could be to call PostString again with a dummy smaller string to release the memory.


Which also brings me to the question of using Posting using an InputStream. Will that also load the whole file into memory? The variable PostInputStream is never closed either.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Passing a string doesn't require any memory. Creating new strings does require some memory.

The problem in your case (if I understand it correctly) is that you create huge strings when you convert the image to base64 strings. The memory will be released when there are no more references to the strings. However if there are several such strings at the same time you will get an out of memory error.

If you can try to avoid creating those strings and send the images as raw bytes.
 
Upvote 0

COBRASoft

Active Member
Licensed User
Longtime User
Hi Erel,

I just tested this...
I would like to send them as a byte array, but I have to put in a map object together with other parameters (for the POST), then I generate JSon from that map object. For some reason this didn't work out because the byte array was not correct in the map...

Greetings,
Sigurd
 
Upvote 0
Top