B4J Question Timer and InvocationTargetException

tchart

Well-Known Member
Licensed User
Longtime User
I have a server app with a timer that runs every 15 seconds. It runs fine for several days and then after a period of time it throws the error below.

I dont see any excess CPU/Memory being used so its not a memory leak etc and the strange thing is that this doesnt happen on WIndows just on my Linux machines.

Any ideas?

B4X:
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4j.object.JServlet.createInstance(JServlet.java:62)
    at anywheresoftware.b4j.object.BackgroundWorkersManager$1.run(BackgroundWorkersManager.java:21)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.RuntimeException: java.lang.StackOverflowError
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:138)
    at anywheresoftware.b4a.objects.Timer$TickTack$1.run(Timer.java:135)
    at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
    at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
    at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:175)
    at nz.ope.qonda.monitor.agent.bkg_collect_procinfo._initialize(bkg_collect_procinfo.java:521)
    ... 7 more

There is nothing tricky in the code

B4X:
Public Sub Initialize
    ClassName = g.GetClassName(Me)
    
    priorSnapshotMap.Initialize
    
    timer1.Initialize("timer1", 15000) ' Every 15 seconds
    timer1.Enabled = True

    StartMessageLoop '<- don't forget!
End Sub

Sub Timer1_Tick
    Logger.Debug("Background - " & ClassName)
    If Main.state <> "running" Then Return
    timer1.Enabled = False
    Collect ' This does the actual work and has a try/catch block around that code
    timer1.Enabled = True
End Sub
 

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Try with calling timer1.enabled = true in another sub with callsubdelayed.

In my little experience I have seen that timers run in different threads (or same thread but new invocations). It seems that the new runnable is being called from the old runnable causing the overflow
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
timer1.Enabled = False Collect ' This does the actual work and has a try/catch block around that code timer1.Enabled = True
what does Collect do? is it using sleep or waitfor? If so then you should wait for Collect to finish before you restart the timer.
 
Upvote 0

tchart

Well-Known Member
Licensed User
Longtime User
what does Collect do? is it using sleep or waitfor? If so then you should wait for Collect to finish before you restart the timer.

The timer is stopped before Collect is called and restarted when it returns. So there should be no overlapping timer ticks.

The function does some data collection, as mentioned it is wrapped in a try catch and I do not see any errors being logged by the function.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
I think that Sleep or Wait For in the Collect sub is a red herring. The stack overflow cannot be building up slowly on the main thread as if it was it would prevent further Timer events, and anything else, on that thread running. I would guess that Collect is starting something that runs on a separate thread and it is there that the stack overflow occurs. So exactly what is Collect doing and is there any possibility that whatever it starts can under some rare circumstance cause a stack runaway - recursion that fails to limit itself would be a classic cause of this.

However it is odd that it does not occur on Windows.
 
Upvote 0

tchart

Well-Known Member
Licensed User
Longtime User
I think that Sleep or Wait For in the Collect sub is a red herring. The stack overflow cannot be building up slowly on the main thread as if it was it would prevent further Timer events, and anything else, on that thread running. I would guess that Collect is starting something that runs on a separate thread and it is there that the stack overflow occurs. So exactly what is Collect doing and is there any possibility that whatever it starts can under some rare circumstance cause a stack runaway - recursion that fails to limit itself would be a classic cause of this.

However it is odd that it does not occur on Windows.
Do you think the stack overflow would be bubbling up from the Collect function?

So Collect does a few things but it basically collects infrastruture information CPU, Memory etc. You could be right regarding the threads. I'll add some extra logging and see where it is falling over.
 
Upvote 0

tchart

Well-Known Member
Licensed User
Longtime User
However it is odd that it does not occur on Windows.
Yeah it is a bit odd. The infrastructure metrics are collected by a cross platform library called OSHI. It provides an abstraction layer between how different metrics are handled by different OS's so it could be a problem with the way the library.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Do you think the stack overflow would be bubbling up from the Collect function?
Not sure what you mean but I think it is a separate thread to the main thread that is misbehaving. From the stack trace it looks like you are starting one or more servlets on a BackgroundWorker thread and my guess is that it is occurring in one of those threads which is going awry for some reason in a recursive loop of some sort.
 
Upvote 0

tchart

Well-Known Member
Licensed User
Longtime User
Not sure what you mean
What I meant was that perhaps the exception is being caused by Collect but not being captured by the exception stack.

The Collect function is wrapped in a try/catch and no error/exception is being logged/trapped. The exception clearly indicates its the timer event hence the confusion.

The Collect function doesnt use any B4X WaitFor/Sleep/CallSub etc methods but it does call some methods from other libraries beyond my control (these should be thread safe). However if this was the case I would expect to see references to these libraries in the exception stack and not Timer$TickTack$1.run etc
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Try/Catch will not catch a stack overflow exception which will be raised regardless because without stack space left it is a fatal problem and execution cannot proceed. The same is true for an out of memory exception. So despite yor Try/Catch in Collect the problem can still be there.
 
Upvote 0
Top