0

I always believed that accessing instanced fields from the instanced method/function should give some performance increase as the data should be "more locally available" (I know this is probably dependent on the system and JVM) as opposed to accessing members from a static context. See the code that illustrates my point:

public class Lecture
{
    public static void main(String[] args)
    {
        hold h1 = new hold();   
        long start1 = System.currentTimeMillis();
            h1.accessOOPs();
        long end1 = System.currentTimeMillis();
        System.out.println("OOPS: "+ (end1 - start1));

        hold h2 = new hold();   
        long start2 = System.currentTimeMillis();
            hold.accessStatic(h2);
        long end2 = System.currentTimeMillis();
        System.out.println("Static (same class): "+ (end2 - start2));

        hold h3 = new hold();   
        long start3 = System.currentTimeMillis();
            accessStatic(h3);
        long end3 = System.currentTimeMillis();
        System.out.println("Static (different class): "+ (end3 - start3));
    }
    public static void accessStatic(hold h)
    {
        for (int i=0;i<h.vars.length;i++)
            h.vars[i] = i;
        for (int i : h.vars)
            h.var1 += i;
        for (int i: h.vars)
            h.name += i;
    }
}
class hold
{
    int var1;
    int vars[] = new int[10000];
    String name;
    public void accessOOPs()
    {
        for (int i=0;i<vars.length;i++)
            vars[i] = i;
        for (int i : vars)
            var1 += i;
        for (int i: vars)
            name += i;
    }
    public static void accessStatic(hold h)
    {
        for (int i=0;i<h.vars.length;i++)
            h.vars[i] = i;
        for (int i : h.vars)
            h.var1 += i;
        for (int i: h.vars)
            h.name += i;
    }
}

In the code I have 3 timed examples where I access/modify attributes in a simple object. The first example calls an instance method in the object so theoretically all the attributes should be faster to access since they are in the same context as the method. The second one calls a static function in the object class and uses the dot operator to access the attributes each time. My assumption was that this would be slower. The third example repeats the same operation as the second one but this time does it within a separate class. I was much confused about the timings I received:

Example run 1:

  • OOPS: 135
  • Static (same class): 130
  • Static (different class): 120

Example run 2:

  • OOPS: 137
  • Procedural (same class): 135
  • Procedural (different class): 128

Consistently the OOPs method beat the Static method when the method was in the separate class but I don't understand why that when the static method was in the same class it would beat the instance method. It was only be a slight margin but it was very consistent. Is this only occurring because the static implementation is caching the reference to the object being accessed? If that was occurring then I would think it wouldn't matter that the static method was in a separate class or not, so I am completely confused. Can anyone answer why the static method are not significantly slower?

Jay Laughlin
  • 154
  • 1
  • 8
  • 1
    Obligatory [How do I write a correct micro-benchmark in Java?](https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java) link. – lexicore Jun 15 '20 at 11:12

1 Answers1

0

Your h3 variable is not passed to any call, and so the computations done on h2 in the 3rd call is different to the computations of h1/h2 earlier.

When doing timing tests you should only measure warmed up code (as JIT compiler changes performance somewhat). If you fix to use h3 and run the code of the main inside a loop you'll see there is very little difference between the runs, the last run I got is

OOPS: 56
Static (same class): 56
Static (different class): 50

You can see that the bytecode for accessOOPs and accessStatic is very similar structure using:

javap -v hold.class > hold.log
javap -v Lecture.class > lecture.log

IN JDK14 they are both 114 items long and different only with field/index positions, there are the differences shown in WINDIFF.EXE

Bytecode diffs accessOOPs vs accessStatic

DuncG
  • 12,137
  • 2
  • 21
  • 33
  • Thank you, h3 was just a typo when culling the example down. But I still tend to get either a little slower performance from the instanced example or if nothing else very similar results. Shouldn't the instanced method have a significant performance boost since it's accesses to the attributes shouldn't need the memory controller whereas the static examples are having to accesses the object with the memory controller - or does JAVA not work that way - or is this just an example of caching the object? – Jay Laughlin Jun 16 '20 at 14:31
  • Unless you run main with a loop over h1-2-3 more than 2-3 times you won't rule out the effect of h1/2 messing up h3 because of the addition garbage collection caused by your string handling. Try also h3-2-1 order. But with one run only, comparative timings are difficult as your step "h.name += i" has a significant memory hit. (If you don't believe me comment out all lines referencing h.name). – DuncG Jun 16 '20 at 15:12
  • As I tested it more I did remove the name and tested it only with a few simple data types - and yes I needed significantly more iterations to get timings. I also tested h1-2-3 in different orders and got similar results (either close timings or instanced method coming in a little slower). I should mention that I have an h0 that calls each method prior to everything which does a warmup phase (maybe not perfect but it stops the first run from taking too much extra time). It just seems to me that the instance method should get significantly better performance than static but that is not the case. – Jay Laughlin Jun 16 '20 at 21:19
  • When not considering inheritance and benefits of overrides, a static method with object parameter you declare is not really different to an instance method with it's implicit "this" parameter. I wouldn't expect performance to be different. – DuncG Jun 17 '20 at 06:51
  • I thought this.x, here the . is a scope resolution operator as opposed to instance.x which here the . should be a memory controller. It is just that java uses the same symbol for both. And in C/C++ at least the memory controller is far more expensive than the scope resolution operator, since the scope resolution operator just has to offset to the data member by doing a little arithmetic with the function pointer since we are in the object memory context already. Or is java really that different and unoptimized (I almost can't believe that though) but this is the heart of my question? – Jay Laughlin Jun 18 '20 at 07:17
  • Use `javap -v` on each of your compiled hold.class and Lecture.class. If you strip out to just the definitions of the methods accessStatic and accessOOPs then run the pair through diff you can see that the bytecode representation is identical apart from index positions of each. – DuncG Jun 18 '20 at 14:56