6

I'm programming a simple game in java. I've made a collision test with 30 FPS, where I had to get the size of the window. Because I haven't had access to the GUI instance, I thought I'd make a shared instance, because this is pretty standard in Objective-C, where I come from.

class GUI extends JFrame {
    private static GUI _sharedInstance;

    public static GUI sharedInstance() {
        if (_sharedInstance == null) {
            _sharedInstance = new GUI();
        }
        return _sharedInstance;
    }
}

But for some reason, it was really slow. Then I replaced the shared instance with public static final instances for the size, and it works fast now, even with 60 FPS or higher.

Can anyone explain me why this happens?

EDIT

So instead of calling GUI.sharedInstance().getWidth(), I'm just calling GUI.windowSize.width. I have used the public static final Dimension windowSize instead.

EDIT

Here's the collision detection. So, instead of calling int width = GUI.kWindowWidth;, I was calling int width = GUI.sharedInstance().getWidth(); before.

// Appears on other side
if (kAppearsOnOtherSide) {
    int width = GUI.kWindowWidth;
    int height = GUI.kWindowHeight;

    // Slow
    // int width = GUI.sharedInstance().getWidth();
    // int width = GUI.sharedInstance().getHeight();

    Point p = this.getSnakeHead().getLocation();
    int headX = p.x;
    int headY = p.y;

    if (headX >= width) {
        this.getSnakeHead().setLocation(new Point(headX - width, headY));
    } else if (headX < 0) {
        this.getSnakeHead().setLocation(new Point(headX + width, headY));
    } else if (headY >= height) {
        this.getSnakeHead().setLocation(new Point(headX, headY - height));
    } else if (headY < 0) {
        this.getSnakeHead().setLocation(new Point(headX, headY + height));
    }
}
Charles
  • 50,943
  • 13
  • 104
  • 142
IluTov
  • 6,807
  • 6
  • 41
  • 103
  • relevant I think - http://stackoverflow.com/questions/4953597/is-there-a-performance-overhead-to-a-private-inner-class-in-java – Caffeinated Nov 22 '12 at 23:01
  • [Actually this SO link is better-](http://stackoverflow.com/questions/690348/java-profiling-private-property-getter-has-large-base-time) – Caffeinated Nov 22 '12 at 23:02
  • 1
    Please explain what you mean. You replaced what with what, and how did you measure the performance difference? – Hot Licks Nov 22 '12 at 23:13
  • 1
    If you simply mean replacing the method with a variable reference well then -- duh!! A method call is pretty much always slower than a variable reference. – Hot Licks Nov 22 '12 at 23:14
  • 1
    How many times is it called per second. It may be quite fast, but if it's getting hammered it's going to affect things. Have you got anything to profile this with? – weston Nov 22 '12 at 23:28
  • @HotLicks I have updated my answer. Yes, of course calling only a variable is faster than calling a method and a variable. But it's not a tiny difference. It seems to be at least like 4-5 times faster... – IluTov Nov 22 '12 at 23:55
  • And I'm doing a lot of collision detection, this simple one line has messed up the whole collision detection – IluTov Nov 22 '12 at 23:58
  • @HotLicks I added the collision detection code, so you can see what I'm talking about. – IluTov Nov 23 '12 at 00:05
  • A variable reference is just that -- one fetch instruction, after the base address (object pointer) has been resolved. A method call is a fetch from the virtual function table, saving registers, pushing the stack pointer, branching to the method, doing that one fetch instruction, reloading saved registers, branching back. Which do you think is faster? – Hot Licks Nov 23 '12 at 00:29
  • (And I see you actually removed TWO method calls in each line you edited.) – Hot Licks Nov 23 '12 at 00:30
  • @HotLicks Right, but I'm also doing `this.getSnakeHead().setLocation(location)`, which isn't a big deal. – IluTov Nov 23 '12 at 00:34
  • @HotLicks I'm doing so much updating overall, it's hard for me to believe that 2 method calls are the reason for messing up the performance – IluTov Nov 23 '12 at 00:38
  • I don't know how hard you're hitting these -- video processing is not my thing. But there is definitely a major difference in the performance of the two. (I presume you're running things long enough for the JITC to kick in -- that'll make about a 100x difference in performance.) – Hot Licks Nov 23 '12 at 00:40
  • @NSAddict Can you back up your belief by actually profiling your code? If the shared instance getter is the culprit, and slows down frame rate to half, it should be very visible in the profile. – millimoose Nov 23 '12 at 01:50
  • I assume this is a typo: `public static sharedInstance()`? Should be `public static GUI sharedInstance()`, right? – Hot Licks Nov 23 '12 at 03:05

1 Answers1

3

I know that this might not be the real answer to the question, but there could be a problem with a race condition. I assume that you are trying to use the lazy/singleton pattern, because the construction of the GUI class is quite expensive and you need only one instance.

Now, what happens? If a thread runs into the if statement body, it creates a new GUI instance. Just before the next assignment, it gets paused by the scheduler. Now another thread pops in, sees that _sharedInstance is still null and creates another GUI instance (and so on...).

Lets assume that there are only two threads. The first thread runs to the end and the second one is continued, now you have two instances of the GUI class. Nobody says that the unassigned GUI instance gets destroyed or garbage collected. That could explain tha 50 % performance loss compared to using finally and assigning the GUI instance directly to _sharedInstance.

See e.g. the Java examples at http://en.wikipedia.org/wiki/Singleton_pattern Double checked locking, inner classes or an enum are the ways you can use.

user3001
  • 3,437
  • 5
  • 28
  • 54
  • 1
    That actually might be the case. I thought some more about it. `new GUI()` starts the main loop. There it updates and checks for the collision. If the initialising of the GUI object isn't complete until the `update()`, a call of `GUI.sharedInstance()` would create a new object. I'll do some testing. Thanks! – IluTov Nov 23 '12 at 07:32
  • 2
    You were right, because I did the initialising and starting of the update thread in the constructor, the update got called so fast that the GUI object wasn't set yet. Therefore the GUI object got initialised even 3 times, and that's why I had so much performance loss. Thanks a lot! – IluTov Nov 27 '12 at 17:01