B4J Code Snippet Garbage collection

Hello

For those of you interested in GC here is a class I have in a B4J server:

B4X:
Sub Class_Globals
 
   Private tmrHook           As Timer
   Private gcTime           As Long
   Private freq_gc           As Int = 1
 
End Sub

Public Sub Initialize
 
 
   ' // 3 seconds
   tmrHook.Initialize("tmrHook", 3000)
   tmrHook.Enabled = True
   threadName = getcurrentThreadName
 
   ' // set the initial GC time
   gcTime =DateTime.Now + (DateTime.TicksPerMinute * freq_gc)
   writelog("Background Hello Helper Thread Started, GC Frequency Check Every " &  freq_gc & " Minutes" )
 
   StartMessageLoop '<- don't forget!
 
End Sub

Sub tmrHook_Tick
 
   ' // do GC
   If gcTime < DateTime.Now Then
       process_gc
       ' // set next time
       gcTime =DateTime.Now + (DateTime.TicksPerMinute * freq_gc)
   End If
 
End Sub

Sub process_gc
 
   Dim jo As JavaObject = Me
 
 
   log("Total designated memory " & jo.RunMethod("getTotal",Null))
   log("Before GC, Java heap currently used by instantiated objects " & jo.RunMethod("getUsed",Null))
   log("Before GC, Current allocated free memory " & jo.RunMethod("getAllocatedFree",Null))
   jo.RunMethod("do_garbage_collection",Null)
   log("After GC, Current allocated free memory " & jo.RunMethod("getAllocatedFree",Null))
   log("After GC, Java heap currently used by instantiated objects " & jo.RunMethod("getUsed",Null))
 
End Sub

Sub getcurrentThreadName As String
    
    Dim t As JavaObject
    Return t.InitializeStatic("java.lang.Thread").RunMethodJO("currentThread", Null).RunMethod("getName", Null)
    
End Sub

#if java

   import java.util.*;
 
   public void do_garbage_collection()   {        
       Runtime rs = Runtime.getRuntime();
       rs.gc();
     }
    
   public long getAllocatedFree() {
       Runtime rs = Runtime.getRuntime();
        return rs.freeMemory();
    }
 
   public long getAllocatedTotal() {
       Runtime rs = Runtime.getRuntime();
        return rs.totalMemory();
    }
 
   public long getUsed() {
       Runtime rs = Runtime.getRuntime();
        return rs.totalMemory() - rs.freeMemory();
    }
 
   public long getTotal() {
       Runtime rs = Runtime.getRuntime();
        return rs.maxMemory();
    }
 
#End If


Regards

John.

EDIT: Please note that in this example the frequency is set to 1 minute, this is just to allow you see the memory metrics. I don't recommend that you use this frequency in a production environment.
 
Last edited:

Jmu5667

Well-Known Member
Licensed User
Longtime User
Hi John, this is quite an old thread, I know, but the topic is interesting to me.
Can you explain the line above?

sure, this code gets the current thread name that a process is running in. I find it quite useful so I can monitor thread activity in a b4j server(no-ui) application.

I just noticed the code was not in the original example, that has now been updated

B4X:
Sub getcurrentThreadName As String
   
    Dim t As JavaObject
    Return t.InitializeStatic("java.lang.Thread").RunMethodJO("currentThread", Null).RunMethod("getName", Null)
   
End Sub
 

jmon

Well-Known Member
Licensed User
Longtime User
EDIT: Please note that in this example the frequency is set to 1 minute, this is just to allow you see the memory metrics. I don't recommend that you use this frequency in a production environment.
Hi, what would be the recommended frequency in production? Also, Java FX already has some sort of garbage collection I believe, is this function redundant, or does it work differently?
 

Jmu5667

Well-Known Member
Licensed User
Longtime User
Hi, what would be the recommended frequency in production? Also, Java FX already has some sort of garbage collection I believe, is this function redundant, or does it work differently?
Hi jmon

I looked into the JAVA VM GC model and it is decides when it will perform it. I use this method on all our B4J servers so I manage when GC is done. If you have a very active server doing a lot client connections and SQL server requests you really want your server app to be at it best performance. I usually do a GC every 15 minutes. I spent a lot of time analysing threading and the memory usage(https://visualvm.github.io/) and understanding how and why it does what it does.

You can do some tests yourself. It's not for everyone, but it serves our company's needs. I hope it it of some value to you.

Regards

John.
 

Peter Simpson

Expert
Licensed User
Longtime User
If you have a very active server doing a lot client connections and SQL server requests you really want your server app to be at it best performance.
I 100% completely agree with this statement.

I have one particular client that has an Ecwid e-commerce store that takes hundreds of orders per day. The background worker app that I developed for them checks for new orders every 10 minutes (any new order are transferred to their online MySQL database) and once per hour the app synchronises their online MySQL database stock levels (about 37,500 items) with their online Ecwid store stock levels, all this is done via the Ecwid API and database connection via the background worker app. The synchronisation is only needed as they also sell in store and have no way to live synchronise their stock with having their custom package developed again which they are thinking about doing and I have given a quite for lately.

The java background worker app starts off at around 65MB of memory usage, after about an hour depending on how many orders have been taken, that memory usage can shoot up to over 350MB (in some cases over 500MB+) until the JVM does it's clean-up. I for one absolutely hate the fact that the background worker app uses resources that are then not fully cleaned-up/released back to the system on completion of processes. My background worker apps use the following code if they are being heavily utilised by my clients.

B4X:
Dim Jo As JavaObject
    Jo.InitializeStatic("java.lang.System").RunMethodJO("gc", Null)
With clients using the Ecwid background worker app, I run the code above every half past the hour after the stock synchronisation routine runs, afterward memory utilisation drops to between 85MB and 105MB

At first when I noticed the memory being used, I thought it was me not closing database connections or doing something incorrectly. It was only after looking more into the memory usage issue, I realised that JVM automatically dealt with clean-up, but I wasn't happy with that so now I just run garbage collection myself every 60 minutes. So, the issue wasn't my coding at all.

I have other clients that I've created background worker apps for, I don't use garbage collection with all of them, just for background workers that are being heavily utilised.

I use ABBackgroundWorkers (extracted from jServer) and not jServer itself. jServer is full of extra features that are not necessary for a background worker app, plus it saves around 2.5+MB on the size of the java file.
 
Last edited:
Top