Search code examples
javaobjectheap-memoryprimitivestack-memory

primitive in object, heap or stack?


Most said that primitive in object are stored in Heap, however, I got different results from the following performance test:

public class Performance {

long sum = 0;

public static void main(String[] args) {
    // TODO Auto-generated method stub
    long startTime = System.currentTimeMillis();
    long pSum = 0;
    for(int i = 0; i < Integer.MAX_VALUE; i++){
        pSum += i;

    }
    long endTime = System.currentTimeMillis();
    System.out.println("time of using primitive:" + Long.toString(endTime - startTime));
    System.out.println(pSum);

    long startTime1 = System.currentTimeMillis();
    Long Sum = 0L;
    for(int i = 0; i < Integer.MAX_VALUE; i++){
        Sum += i;
    }
    long endTime1 = System.currentTimeMillis(); 
    System.out.println("time of using object:" + Long.toString(endTime1 - startTime1));
    System.out.println(Sum);

    Performance p = new Performance();
    long startTime2 = System.currentTimeMillis();
    for(int i = 0; i < Integer.MAX_VALUE; i++){
        p.sum += i;
    }
    long endTime2 = System.currentTimeMillis();
    System.out.println("time of using primitive in object:" + Long.toString(endTime2 - startTime2));
    System.out.println(p.sum);
}

}

The results look like this:

time of using primitive:1454
2305843005992468481
time of using object:23870
2305843005992468481
time of using primitive in object:1529
2305843005992468481

We can find the time of using primitive and using primitive in object are almost same. So I am confused if primitives in objects are stored in Heap. And why the time cost of using primitive and using primitive in object are almost same?


Solution

  • When you go

    Long sum;
    ...
    sum += 1;
    

    the JVM, in theory, allocates a new Long each time, cause Longs are immutable. Now, a really smart compiler could do something smart here, but this explains why your time for the second loop is so much larger. It is allocating Integer.MAXINT new Sum objects. Yet another reason Autoboxing is tricky.

    The two other loops do not require allocating new Objects. One uses a primitive int, and in the other you can increment Performance.sum without needing to allocate a new Performance each time. Accessing the primitive int on the stack or in the heap should be roughly equally fast, as shown.

    Your timings have very little to do with heap vs. stack speed of access, but everything to do with allocating large numbers of Objects in loops.

    As others have noted, micro benchmarks can be misleading.