[SOLVED] SimpleApplication not shutting down

Hi!

I’m creating a game that uses multiple AppStates.
All is perfect, but there is only an issue… when I close the game (with Escape key), the frame isn’t visible but the process is still running in background. Why?
I’m not using other threads.

I call:

inputManager.clearMappings();

in the app initialization to remove the default mappings because I want to override them in the AppStates, so I created another listener: when I press Escape it calls first app.stop() and then cleanup() to cleanup the AppState.

protected ActionListener exitListener = new ActionListener(){
    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
        if(isPressed){
            app.stop();
            cleanup();
        }
    }
};

But I think that the issue isn’t in this listener because it remains also when I close the window with the “X”.

So, can you help me? Thanks!

Do you use a thread pool in your application? Like ScheduledThreadPoolExecutor or the like?

No Timers… no ThreadPools… etc.? No AWT or Swing windows created without being disposed?

I think you must be somewhere.

Anything!

Run you app from the command line. Once you hit escape I guess the command line never returns. Hit Ctrl-break and you will get a thread dump.

Somewhere you are creating a thread. This might help you figure out which non-daemon thread is still alive.

Ok!

The result of the thread dump is:

Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):

"Timer-0" #23 prio=5 os_prio=0 tid=0x0000000016488800 nid=0x17d8 in Object.wait(
) [0x0000000016eff000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Unknown Source)
        at java.util.TimerThread.mainLoop(Unknown Source)
        - locked <0x00000000f0220fb8> (a java.util.TaskQueue)
        at java.util.TimerThread.run(Unknown Source)

"DestroyJavaVM" #20 prio=5 os_prio=0 tid=0x00000000028d0800 nid=0x162c waiting o
n condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"TimerQueue" #18 daemon prio=5 os_prio=0 tid=0x00000000163e4800 nid=0xc7c waitin
g on condition [0x0000000019aef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000f0f5c818> (a java.util.concurrent.lock
s.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(Unknown Source)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
.await(Unknown Source)
        at java.util.concurrent.DelayQueue.take(Unknown Source)
        at javax.swing.TimerQueue.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"D3D Screen Updater" #17 daemon prio=7 os_prio=1 tid=0x00000000163e4000 nid=0x94
0 in Object.wait() [0x00000000199ef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at sun.java2d.d3d.D3DScreenUpdateManager.run(Unknown Source)
        - locked <0x00000000f0f60258> (a java.lang.Object)
        at java.lang.Thread.run(Unknown Source)

"AWT-Windows" #12 daemon prio=6 os_prio=0 tid=0x0000000015d2c800 nid=0xfa0 runna
ble [0x0000000016c0f000]
   java.lang.Thread.State: RUNNABLE
        at sun.awt.windows.WToolkit.eventLoop(Native Method)
        at sun.awt.windows.WToolkit.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"Java2D Disposer" #10 daemon prio=10 os_prio=2 tid=0x0000000015d29000 nid=0xc50
in Object.wait() [0x0000000016a0f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000f0e02c48> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x00000000f0e02c48> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at sun.java2d.Disposer.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x000000001455c000 nid=0x10e4 ru
nnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x0000000014501000 nid=0x189
0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000144fc000 nid=0x18d
0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000144f8000 nid=0x1588 r
unnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000144f3000 nid=0x1828
 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000144e8800 nid=0xb94 in Objec
t.wait() [0x000000001522f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x00000000f0f40c98> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000029bc800 nid=0xe64
 in Object.wait() [0x000000001512e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Unknown Source)
        at java.lang.ref.Reference.tryHandlePending(Unknown Source)
        - locked <0x00000000f0f3f798> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)

"VM Thread" os_prio=2 tid=0x00000000144c6000 nid=0x1530 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000028e6000 nid=0x1304 runn
able

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000028e8000 nid=0xd4c runna
ble

"VM Periodic Task Thread" os_prio=2 tid=0x000000001459a000 nid=0x1858 waiting on
 condition

JNI global references: 502

Heap
 PSYoungGen      total 14336K, used 9580K [0x00000000f0000000, 0x00000000f100000
0, 0x0000000100000000)
  eden space 12288K, 61% used [0x00000000f0000000,0x00000000f075f068,0x00000000f
0c00000)
  from space 2048K, 99% used [0x00000000f0e00000,0x00000000f0ffc278,0x00000000f1
000000)
  to   space 2048K, 0% used [0x00000000f0c00000,0x00000000f0c00000,0x00000000f0e
00000)
 ParOldGen       total 32768K, used 5962K [0x00000000d0000000, 0x00000000d200000
0, 0x00000000f0000000)
  object space 32768K, 18% used [0x00000000d0000000,0x00000000d05d29b0,0x0000000
0d2000000)
 Metaspace       used 18249K, capacity 18541K, committed 18688K, reserved 106496
0K
  class space    used 2128K, capacity 2202K, committed 2304K, reserved 1048576K

The Timer-0 thread and the DestroyJavaVM threads aren’t daemon.
I think that the Timer-0 thread is associate to a Timer or not?
But I haven’t any Timer in my code…

Do you override destroy without calling super maybe? Stab in the dark.

No, I never overridden destroy.

Well then we are all lost and need more info I’m afraid.

The dump doesn’t say anything?

Do a search for the name of the timer thread. Something named it.

How?

How do you search through source code? Really?

Ah sorry :sweat_smile:

I only found a Timer object called scheduler, but I never started it in the code.

IIRC, Timers start their threads on construction. Is this Timer constructed (i.e. new Timer()) or declared (i.e. Timer t;)?
If this Timer is constructed and thus indeed running, you can close it by calling Timer#cancel() or Timer#purge() (docs).

Edit: quote from docs:

… By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer’s task execution thread rapidly, the caller should invoke the timer’s cancel method.

Not sure if it was fixed, but when I last used nifty, it also stopped my program from exiting.

Something you do is creating a Timer.

OKAY!!!

The issue was the Timer initialization…
From this day i’ll hate Timers.
I used the timer to do some things and then I’ve eliminated that code, but I forgot to delete the Timer scheduler = new Timer().

Thanks!!!

1 Like

Well just a rule of thumbs. Every single time I encountered this issue it was a thread cleanup issue. It always is.
And yes, a java Timer spawns a thread.

It was fixed. There is no JME release that has this bug, it was fixed just in time for JME 3.1.