B4J Question [SOLVED - sort of] Forcing garbage collection

JackKirk

Well-Known Member
Licensed User
Longtime User
I put this up for discussion as I'm not overly happy with it - but it seems to work.

I have a large B4J app that runs on Windows 10. The app does some serious image processing and is fed new images at a rapid rate of knots. The app can handle multiple images in parallel - currently set to 4.

There are no #VirtualMachineArgs settings - all defaults.

When it is going flat out I notice that the memory usage of the app (as shown by Windows Task Manager) slowly but surely rises until it gets to about 2.5GB when the various steps in the processing start shedding (I have lots of error detection in each step).

This results in the images currently being processed not being processed - which I have a recovery mechanism for.

Ultimately it falls over and is automatically restarted.

I obviously started looking for memory leaks etc to no avail.

In quiet desperation, I ported this:

https://www.b4x.com/android/forum/threads/solved-how-to-force-a-garbage-collection.68588/

And copied agraham's Threading library from B4A\Additional Libraries to B4J\Additional Libraries - which agraham says should work - and it seems to.

After each image is processed I now force a garbage collection - and lo and behold the memory usage of the app (as shown by Windows Task Manager) settles at about 1.2-1.6GB for multiple thousands of images processed. With no obvious detrimental side effects.

Any suggestions/comments?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
There are very rare cases where forcing GC really helps.
My guess is that you have a memory leak somewhere and the OOM will eventually happen with the GC call.

Also:

1. There is nothing bad with increasing the heap size. If your computer has more memory then use it. I have processes that run with a limit of 64gb on a server with 128gb.
2. Make sure to use a 64 bit JDK.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
My guess is that you have a memory leak somewhere
Are there any tools/techniques that can help to isolate memory leaks in B4J apps?
the OOM will eventually happen with the GC call.
Testing to date over several days - 14,000 odd images processed per day - seems to result in a memory usage that consistently stays under about 1.6GB - when it was previously bombing at about 2.5GB (which used to happen at about 6-7,000 images)
Make sure to use a 64 bit JDK.
Tick
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
My guess is that you have a memory leak somewhere
Thinking about this overnight - between fireworks on Sydney Harbour...

My (limited) understanding of memory leaks is that they are bits of memory that still have some sort of reference to them - technically they are "required" but in reality, they aren't. And therefore they are not candidates for garbage collection - so they accumulate.

As my forced garbage collection solution seems to work doesn't it imply I don't have a memory leak?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
I installed VisualVM as agraham suggested and ran it with the subject app under full load (about a 6,000 image backlog).

This screenshot is of the version of the app that forces garbage collection:
With forced GC.png


And this is of the version that does not force garbage collection:
Without forced GC.png


I am a complete novice on this stuff but the second screenshot seems to suggest to me that there is no memory leak

What the second screenshot also seems to be telling me is that there are massive fluctuations in "used heap" when there is no forced garbage collection.

I'm wondering if the reason the "no forced garbage collection" version of the app eventually falls over is because there is an out-of-the-blue major jump in "used heap" that the normal garbage collection can't keep up with.

All thoughts and suggestions welcome...
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Increase the max heap size and run it for a while.
I've set:

#VirtualMachineArgs: -Xms2048m -Xmx4096m

and turned forced garbage collection off.

When I run it VirtualVM says this in the Heap panel:

Max: 2,069,889,048 B

Does this make sense?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Ultimately I set:

#VirtualMachineArgs: -Xms2048m -Xmx4096m

and turned forced garbage collection on.

I'm just playing safe - and everything works - no bombing and no obvious detrimental side effects.

For anyone interested, this is my class to force garbage collection:
B4X:
'************************************************************************************
'
'This class module forces a java garbage collection, see:
'
'    https://www.b4x.com/android/forum/threads/forcing-garbage-collection.158324/
'
'Calls:
'
'   Initialize
'
'   Fire
'
'Requirements:
'
'         Threading (version 1.10 or later) - pinched from B4A
'         jReflection (version 1.20 or later)
'
'Update history:
'
'   30 Dec 23 - 1.0
'
'************************************************************************************
Sub Class_Globals
    Private fx As JFX
    Private Force_GC_Thread As Thread
    Private Force_GC_Reflector As Reflector
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
  
End Sub

Public Sub Fire

    'Set up Force_GC thread
    Force_GC_Thread.Initialise("Force_GC")

    'Start thread to force OOM
    Dim args(0) As Object
    Force_GC_Thread.Start(Me, "Force_GC_Process", args)

    'This loop keeps control here until thread dies, should take a couple millisec
    Do While Force_GC_Thread.Running
 
    Loop

End Sub

Private Sub Force_GC_Process

    'Find maximum memory process can use
    Force_GC_Reflector.Target = Force_GC_Reflector.RunStaticMethod("java.lang.Runtime", "getRuntime", Null, Null)
    Private Max_memory As Long = Force_GC_Reflector.RunMethod("maxMemory")

    'Attempt to create an array that would fill maximum memory - will force a garbage
    'collection then bomb with OOM which will be caught by Force_GC_Ended
    Private OOM_bomb(Max_memory / 8) As Double

End Sub

Private Sub Force_GC_Ended(Fail As Boolean, Error As String)

End Sub

Which is fired by:
B4X:
    'Force a garbage collection
    Private Force_GC As Force_Garbage_Collection
    Force_GC.Initialize
    Force_GC.Fire

And I managed to learn about java profilers which might prove useful at some point.
 
Upvote 0

Swissmade

Well-Known Member
Licensed User
Longtime User
I've set:

#VirtualMachineArgs: -Xms2048m -Xmx4096m

and turned forced garbage collection off.

When I run it VirtualVM says this in the Heap panel:

Max: 2,069,889,048 B

Does this make sense?
If you set -Xms2048m -Xmx4096m to the same size Java don't have to calculate the heap size but reserve it.
Source from Oracle when I was checking for a better performance of 1 B4J App
 
Upvote 0
Top