Android Question Error OUT OF MEMORY

amorosik

Expert
Licensed User
I'm using a six column FlexGrid to load a list of items, the last column being the price
The grid is fed by a query that joins the Items table and the Prices table with an inner join of the type
Query Selezione:
"SELECT a.COD_INT, a.DESCR, a.UNI_MIS, ifnull(p.PREZZO,0) as PRZ, ifnull(DISPONIBILITA,0) as DISP, ifnull(ESISTENZA,0) as ESIST  FROM ARTICOLI a LEFT JOIN PREZZI p ON a.cod_int=p.codice_articolo and p.codice_listino=" & codice_listino_attuale

The query returns about 1500 rows, each with 6 fields
The FlexGrid is loaded with the classic cycle that reads the query on the db from the rows and sets the fields of each row

B4X:
flexArticoli.ClearRows
Dim rs As ResultSet = Starter.oSQL.ExecQuery(curselect  & curwhere & " " & cursort )
Do While rs.NextRow
    flexArticoli.AddRow(Array As Object(rs.GetString("COD_INT"), rs.GetString("DESCR"), rs.getstring("UNI_MIS"),NumberFormat2(rs.getstring("PRZ"),1,2,2,False),rs.getstring("ESIST"),rs.getstring("DISPON")),True)
    Loop
    rs.Close
       
Log(flexArticoli.RowCount)

After a few minutes of operation both in debug and in release, the indicated error pops up and the app is brutally interrupted
What can cause the problem?
How to monitor the amount of memory that the error is indicating and how to figure out what the maximum usable limit is?
Is it possible to catch the error and perform some operations that allow to release part of the occupied memory?
B4A 11.80 64bit, B4A Bridge 2.62, On Tablet Samsung Tab 6 Lite

Error OUT OF MEMORY:
2023-03-24 07:25:58 752 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
Ping verso consolle
2023-03-24 07:26:00 753 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
2023-03-24 07:26:02 031 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
java.lang.OutOfMemoryError: Failed to allocate a 172816 byte allocation with 2031200 free bytes and 1983KB until OOM, target footprint 268435456, growth limit 268435456; giving up on allocation because <1% of heap free after GC.
    at android.view.ViewGroup.addInArray(ViewGroup.java:5586)
    at android.view.ViewGroup.addViewInner(ViewGroup.java:5499)
    at android.view.ViewGroup.addView(ViewGroup.java:5296)
    at android.view.ViewGroup.addView(ViewGroup.java:5268)
    at anywheresoftware.b4a.objects.PanelWrapper.AddView(PanelWrapper.java:65)
    at b4a.example.flexgrid._addview(flexgrid.java:326)
    at b4a.example.flexgrid._createrow(flexgrid.java:1158)
    at b4a.example.flexgrid$ResumableSub_CreateGrid.resume(flexgrid.java:959)
    at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1717)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:226)
    at android.os.Looper.loop(Looper.java:313)
    at android.app.ActivityThread.main(ActivityThread.java:8772)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
 
Solution
I'm using a six column FlexGrid to load a list of items, the last column being the price
The grid is fed by a query that joins the Items table and the Prices table with an inner join of the type
Query Selezione:
"SELECT a.COD_INT, a.DESCR, a.UNI_MIS, ifnull(p.PREZZO,0) as PRZ, ifnull(DISPONIBILITA,0) as DISP, ifnull(ESISTENZA,0) as ESIST  FROM ARTICOLI a LEFT JOIN PREZZI p ON a.cod_int=p.codice_articolo and p.codice_listino=" & codice_listino_attuale

The query returns about 1500 rows, each with 6 fields
The FlexGrid is loaded with the classic cycle that reads the query on the db from the rows and sets the fields of each row

B4X:
flexArticoli.ClearRows
Dim rs As ResultSet = Starter.oSQL.ExecQuery(curselect  & curwhere & " " & cursort )
Do While...

Filippo

Expert
Licensed User
Longtime User
I'm using a six column FlexGrid to load a list of items, the last column being the price
The grid is fed by a query that joins the Items table and the Prices table with an inner join of the type
Query Selezione:
"SELECT a.COD_INT, a.DESCR, a.UNI_MIS, ifnull(p.PREZZO,0) as PRZ, ifnull(DISPONIBILITA,0) as DISP, ifnull(ESISTENZA,0) as ESIST  FROM ARTICOLI a LEFT JOIN PREZZI p ON a.cod_int=p.codice_articolo and p.codice_listino=" & codice_listino_attuale

The query returns about 1500 rows, each with 6 fields
The FlexGrid is loaded with the classic cycle that reads the query on the db from the rows and sets the fields of each row

B4X:
flexArticoli.ClearRows
Dim rs As ResultSet = Starter.oSQL.ExecQuery(curselect  & curwhere & " " & cursort )
Do While rs.NextRow
    flexArticoli.AddRow(Array As Object(rs.GetString("COD_INT"), rs.GetString("DESCR"), rs.getstring("UNI_MIS"),NumberFormat2(rs.getstring("PRZ"),1,2,2,False),rs.getstring("ESIST"),rs.getstring("DISPON")),True)
    Loop
    rs.Close
      
Log(flexArticoli.RowCount)

After a few minutes of operation both in debug and in release, the indicated error pops up and the app is brutally interrupted
What can cause the problem?
How to monitor the amount of memory that the error is indicating and how to figure out what the maximum usable limit is?
Is it possible to catch the error and perform some operations that allow to release part of the occupied memory?
B4A 11.80 64bit, B4A Bridge 2.62, On Tablet Samsung Tab 6 Lite

Error OUT OF MEMORY:
2023-03-24 07:25:58 752 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
Ping verso consolle
2023-03-24 07:26:00 753 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
2023-03-24 07:26:02 031 Mqtt.Timer1sec_tick mqtt_connected=true Mqtt_client.Connected=true
java.lang.OutOfMemoryError: Failed to allocate a 172816 byte allocation with 2031200 free bytes and 1983KB until OOM, target footprint 268435456, growth limit 268435456; giving up on allocation because <1% of heap free after GC.
    at android.view.ViewGroup.addInArray(ViewGroup.java:5586)
    at android.view.ViewGroup.addViewInner(ViewGroup.java:5499)
    at android.view.ViewGroup.addView(ViewGroup.java:5296)
    at android.view.ViewGroup.addView(ViewGroup.java:5268)
    at anywheresoftware.b4a.objects.PanelWrapper.AddView(PanelWrapper.java:65)
    at b4a.example.flexgrid._addview(flexgrid.java:326)
    at b4a.example.flexgrid._createrow(flexgrid.java:1158)
    at b4a.example.flexgrid$ResumableSub_CreateGrid.resume(flexgrid.java:959)
    at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1717)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:226)
    at android.os.Looper.loop(Looper.java:313)
    at android.app.ActivityThread.main(ActivityThread.java:8772)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
Have you tried this yet?

If that doesn't help, then you should try xcustomlistview-lazy-loading.
 
Upvote 0
Solution

amorosik

Expert
Licensed User
With SetApplicationAttribute(android:largeHeap, "true") seem to be ok now
Many thanks

However, I believe that the second possibility, which basically loads one data page at a time, is much more efficient, because in my case I would have to select only 20 records instead of about 1500, and this advantage increases as the volume of data increases to view
 
Upvote 0

Filippo

Expert
Licensed User
Longtime User
However, I believe that the second possibility, which basically loads one data page at a time, is much more efficient, because in my case I would have to select only 20 records instead of about 1500, and this advantage increases as the volume of data increases to view

yes, that is also the best solution. :)
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
With SetApplicationAttribute(android:largeHeap, "true") seem to be ok now
You are probably sick of hearing about parameterized queries. But in your case, you should take it seriously as your data appears to be very valuable to dismiss it. Here is how I would code it:
B4X:
Dim curselect As String = $"SELECT a.COD_INT, a.DESCR, a.UNI_MIS, ifnull(p.PREZZO,0) as PRZ,
    ifnull(DISPONIBILITA,0) as DISP, ifnull(ESISTENZA,0) as ESIST 
     FROM ARTICOLI a LEFT JOIN PREZZI p ON a.COD_INT=p.codice_articolo AND p.codice_listino = ?"$        
    Starter.oSQL.ExecQuery2($"${curselect}  ${curwhere} ${cursort})"$, Array As String(codice_listino_attuale))
Also, I would have tried an Async select statement before I increased the heap. Something like this:
B4X:
Dim AsyncSelect As Object = Starter.oSQL.ExecQueryAsync("SQL", $"${curselect}  ${curwhere} ${cursort})"$, Array As String(codice_listino_attuale))
    Wait For (AsyncSelect) SQL_QueryComplete (Success As Boolean, rs  As ResultSet)
    If Success Then
        'populate the grid
    Else
        
    End If
 
Upvote 0

amorosik

Expert
Licensed User
It seems that using the row SetApplicationAttribute(android:largeHeap, "true") on the manifest, Android wants to close the app at all costs, even after a few seconds of non-use he assumes that the app is 'locked'
And so I'm going back to using the app without the largeHeap:true line
Strangely, the problem no longer occurs, although I think I haven't substantially changed the code where the problem occurred
Well, these things look alive
 
Upvote 0
Top