Headless mode does not work twice in the same JVM process

Hi!

I’m trying to use Headless mode while developing my game for testing purposes. But I rarely shut down my JVM process, because it takes time to start it up again. Everything worked fine until I wanted to run my game in Headless mode. When I try to run my game in Headless mode for the second time in the same JVM process, simpleUpdate gets called only once, without any Exception being thrown.

To be clear (in every following scenario, the game instances always run in the same JVM process):

Running the game in Display mode multiple times, after each other, works fine.
Running two instances of the game in Headless mode in parallell works fine.
Running the game in Display mode and then Headless mode works fine.
Running the game twice in a row in Headless mode DOES NOT work fine.

So, as far as I can tell, one can not start an app in Headless mode without running into problems if an app in Headless mode has stopped in the same JVM process. (EDIT: Added “without running into problems” as one can start one.)

Can I fix this? Is this a known issue? It seems weird that running the game again works in Display mode but not in Headless mode.

well without code or any idea of what youre doing its hard to help you. I will say you can indeed use multiple instances of headless mode in one jvm because I used to do it when testing out spider monkey a few months ago.

The problem is most likely with clojure/lack of support for clojure (which i beleive you mentioned you were using) or your code.

You could try doing what youre trying to do with regular java/the regular jvm and see if you still have the same issue

Edited this post because it was very long, and mostly worthless now. Check this instead: http://hub.jmonkeyengine.org/forum/topic/headless-mode-does-not-work-twice-in-the-same-jvm-process/#post-239167

I’d suspect that something isn’t properly shutdown in headless mode, though I’d have no idea what that might be.

I’m a bit suspicious about what those core/stop calls do. Do they forcefully terminate threads? There are race conditions associated with that kind of stuff in Java; you usually shut down threads by telling them to stop and letting them do their exit processing on their own. (Java cannot simply kill threads because it does not know about external resources like file handles and such.)

In stop I call stop on Kryonet (networking lib, shutting down the socket etc.) and stop on the SimpleApplication. In the server I call stop in Kryonet and just end the loop (not loop anymore, nothing forceful).

EDIT: I tried not starting or stopping kryonet at all, but no difference.

EDIT 2: Now I have basically commented out everything. I just extend SimpleApplication, but doing nothing in simpleInit or simpleUpdate; yet the problem persists.

[java]package strongdk.experiments;

import com.jme3.app.SimpleApplication;
import com.jme3.system.JmeContext;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*

  • @author Daniel Strong aka icamefromspace
    */
    public class Simple extends SimpleApplication{

    private static int count = 0;
    private final int num;

    public static void main(String[] args){
    Logger.getLogger(“org.lwjgl”).setLevel(Level.SEVERE);
    Logger.getLogger(“com.jme3”).setLevel(Level.SEVERE);
    Logger.getLogger("").setLevel(Level.SEVERE);

         new Simple().start(JmeContext.Type.Headless);
    

    }

    public Simple() {
    count++;
    num = count;
    }

    @Override
    public void simpleInitApp() {
    System.out.printf(“simpleInitApp(): %s\n”, num);
    }

    @Override
    public void simpleUpdate(float tpf) {
    System.out.printf(“simpleUpdate(): %s\n”, num);
    stop();
    new Simple().start(JmeContext.Type.Headless);
    }

}
[/java]

output is:

simpleInitApp(): 1
simpleUpdate(): 1
simpleInitApp(): 2
simpleUpdate(): 2
simpleInitApp(): 3
simpleUpdate(): 3
simpleInitApp(): 4
simpleUpdate(): 4
simpleInitApp(): 5
simpleUpdate(): 5
simpleInitApp(): 6
simpleUpdate(): 6
simpleInitApp(): 7
simpleUpdate(): 7
simpleInitApp(): 8
simpleUpdate(): 8
simpleInitApp(): 9
simpleUpdate(): 9
simpleInitApp(): 10
simpleUpdate(): 10
simpleInitApp(): 11
simpleUpdate(): 11
simpleInitApp(): 12
simpleUpdate(): 12
simpleInitApp(): 13
simpleUpdate(): 13
simpleInitApp(): 14
simpleUpdate(): 14
.
.
.
.

Youre doing something wrong, or something with clojure doesnt work with jme.

Your code worked. But I said simpleUpdate runs once. What about this though? This is basically what I do. It does not work for me in Java (yes, this code):

[java]import com.jme3.app.SimpleApplication;
import com.jme3.system.JmeContext;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Jmetest extends SimpleApplication{
public static void main(String[] args){
try {
Logger.getLogger(“org.lwjgl”).setLevel(Level.SEVERE);
Logger.getLogger(“com.jme3”).setLevel(Level.SEVERE);
Logger.getLogger("").setLevel(Level.SEVERE);

        Jmetest t1 = new Jmetest();
        t1.start(JmeContext.Type.Headless);
        Thread.sleep(2000);
        t1.stop();

        Jmetest t2 = new Jmetest();
        t2.start(JmeContext.Type.Headless);
        Thread.sleep(2000);
        t2.stop();
    }
    catch (Exception e)
    {
    }
}

public Jmetest() {
}

@Override
    public void simpleInitApp() {
        System.out.println("simpleInitApp() <-");
    }

@Override
    public void simpleUpdate(float tpf) {
        try {
            Thread.sleep(50);
            System.out.println("simpleUpdate()");
        } catch (Exception e) {}
    }

}[/java]

Output:

simpleInitApp() <-
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleUpdate()
simpleInitApp() <-
simpleUpdate()

Btw, sorry for not posting code like this sooner.

Also, this is weird:

[java]import com.jme3.app.SimpleApplication;
import com.jme3.system.JmeContext;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Simple extends SimpleApplication{

private int counter = 0;
private long t1;
private long t2;

public static void main(String[] args){
    Logger.getLogger("org.lwjgl").setLevel(Level.SEVERE);
    Logger.getLogger("com.jme3").setLevel(Level.SEVERE);
    Logger.getLogger("").setLevel(Level.SEVERE);

    new Simple().start(JmeContext.Type.Headless);
}

public Simple() {
    t1 = System.currentTimeMillis();
}

@Override
    public void simpleInitApp() {
        System.out.println("simpleInitApp() &lt;-");
    }

@Override
    public void simpleUpdate(float tpf) {
        System.out.println("simpleUpdate()");
        if (counter++ == 1) {
            t2 = System.currentTimeMillis();
            System.out.println(t2 - t1);
            stop();
            new Simple().start(JmeContext.Type.Headless);
        }
    }

}[/java]

Output:

simpleInitApp() <-
simpleUpdate()
simpleUpdate()
223
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
206
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
240
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
274
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
308
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
341
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
375
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
408
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
442
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
476
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
510
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
544
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
577
simpleInitApp() <-
simpleUpdate()
simpleUpdate()
611
simpleInitApp() <-
simpleUpdate()

seems to work as expected?

Where’s the problem in the first example?
For the second example, is start() firing up a separate thread, or are you now having a stalled update loop, inside of which the next server is running? In general it might be a good idea to check whether start() and stop() are just doing thread setup/shutdown, or doing stuff directly. In the latter case, you don’t want to start an application from inside the update loop.

@toolforger @icamefromspace In the first example, simpleUpdate is called only once for the second instance during the 2 seconds.

In the second example, start is starting a new thread that calls simpleUpdate. I don’t get why the time is increasing. It should not. And, the time is actually being spent between the first and second call to simpleUpdate. It stalls after the first simpleUpdate.

edit: nevermind i see what youre doing.

my only guess is that something is happening thats causing you to get worse framerate, probbaly creating a new app is resource heavy. simple update isnt going to be called at a constant rate. (thats what it passes in the tpf, or time per frame variable)

@icamefromspace It’s not just worse framerate, especially in the first example. The app just freezes after the first simpleUpdate call of the second app instance. It has 2 seconds to make another call, but it never comes. And the problem does not happen in Display mode, which should be more resource heavy, presumably. Did you run it? It’s more noticable when you see it yourself. :stuck_out_tongue:

try removing your second stop() in that example, or increase the sleep to something like 10 seconds. i bet its doing garbage collection… because like i said assurably starting a new application is probably resource heavy… and simpleUpdate is not called at a constant rate.

I increased it to 10 s, and it starts updating after like 3 seconds. But I don’t think it’s GC. Garbage collection of like 50 MBs of memory shouldn’t take 3 seconds, right? And again, there is no pause for Display mode.

i cant really answer this, im not actually a jme developer. its perhaps is also just trying to do internal cleanup on its own, possibly iterating through a lot of stuff to do various checks. I doubt this is a scenario that gets tested often as rapidly starting and stopping an application instance isnt common usage of the SimpleApplication class.

I wouldn’t do what the second example does; trying to start the second application from inside the first application’s update loop is going to violate all kinds of assumptions in the framework code.

Stylistic nitpick: Never catch and ignore exception (except where that’s intentional, in which case a comment should explain why).
I don’t think any exceptions are being eaten this way, but adding an e.printStackTrace() wouldn’t hurt and will alert you if exceptions start flying.

Try adding System.nanoTime() to the output and post that, this might contain clues.

I’d single-step through the t1.stop() and t2.start() calls and see what’s happening under the hood.

<cite>@toolforger said:</cite> Stylistic nitpick: Never catch and ignore exception (except where that's intentional, in which case a comment should explain why). I don't think any exceptions are being eaten this way, but adding an e.printStackTrace() wouldn't hurt and will alert you if exceptions start flying.

Or

public static void main(String[] args) throws Exception { …

and don’t catch them at all, will be the same but with less code :slight_smile:

@toolforger Yeah, well my style does not even involve Java. :stuck_out_tongue:

About the second example: After simpleUpdate has started another instance, it should return, so I thought it should be OK. Maybe not. Anyway, it’s the first example I care most about anyway.

hi,
Pleas someone help, I was making game client server architecture. it was working, player can move in all direction but on server i was using :

getGameWorldById(worldId).start();

And i decided use:

getGameWorldById(worldId).start(JmeContext.Type.Headless);

And it’s gone terrible, nothing was working, simpleUpdate looping each 5-15 seconds, just disaster. Phisics is not calculating anymore.
sometimes simpleUpdate loop runs fast and after while stops and go slow.

[java]
@Override
public void simpleUpdate(float ftp) {

    for (Player pl : allRoomPlayers) {
        System.out.println(pl.getName() + " zaidejas " + pl.getPlayerController().B_FOWARD);
        Vector3f modelFowardDir = pl.getPlayerController().getPlayerNode().getWorldRotation().mult(Vector3f.UNIT_Z);

        //go foward or backward

        walkDirection.set(0, 0, 0);
        if (pl.getPlayerController().B_FOWARD) {
            System.out.println("foward pressed ");
            walkDirection.addLocal(modelFowardDir.mult(14f));                 
            pl.getPlayerController().getPlayerControl().setWalkDirection(walkDirection);
        } else if (pl.getPlayerController().B_BACKWARD) {
            walkDirection.addLocal(modelFowardDir.mult(pl.getSpeed()).negate());              
        } 
     
        pl.getPlayerController().getPlayerControl().setWalkDirection(walkDirection);


         positionMessage.viewDirection = pl.getPlayerController().getPlayerControl().getViewDirection();
        positionMessage.location = pl.getPlayerController().getPlayerNode().getLocalTranslation();
        positionMessage.name = pl.getName();
        this.sendToAllPlayers(positionMessage);

    }
}

[/java]
this is part of my code, it was working, but after changed mode in headless everything have stop. Can someone give advice how i can fix it ?