Bhavesh
Bhavesh

Reputation: 4677

Where and when the use of primitive data types in Java is effectively appropriate?

Consider the following two segments of code in Java,

Integer x=new Integer(100);
Integer y=x;
Integer z=x;


System.out.println("Used memory (bytes): " +   
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));

In which the memory usage was when tested on my system : Used memory (bytes): 287848


and

int a=100;
int b=a;
int c=a;

System.out.println("Used memory (bytes): " + 
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));

In which the memory usage was when tested on my system : Used memory (bytes): 287872



and the following

Integer x=new Integer(100);       
System.out.println("Used memory (bytes): " +  
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));

and

int a=100;        
System.out.println("Used memory (bytes): " + 
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));

in both of the above cases, the memory usage was exactly the same when tested on my system : Used memory (bytes): 287872



The statement

System.out.println("Used memory (bytes): " + 
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));

will display the total memory currently in use [Total available memory-Currently free available memory], (in bytes).


I have alternatively verified through the above mentioned methods that in the first case the memory usage (287848) was lower than the second one (287872) while in the rest of the two cases it was exactly the same (287872). Of course and obviously, it should be such because in the very first case, y and z contain a copy of the reference held in x and they all (x, y and z) point to the same/common object (location) means that the first case is better and more appropriate than the second one and in the rest of the two cases, there are equivalent statements with exactly the same memory usage (287872). If it is so, then the use of primitive data types in Java should be useless and avoidable though they were basically designed for better memory usage and more CPU utilization. still why do primitive data types in Java exist?


A question somewhat similar to this one was already posted here but it did not have such a scenario.

That question is here.

Upvotes: 5

Views: 2293

Answers (10)

Matthew Cline
Matthew Cline

Reputation: 2376

As for "where and when": use the non-primitive types where an Object is required, and the primitives everywhere else. For example, the types of a generic can't be primitive, so you can't use primitives with them. Even before generics were introduced, things like HashSet and HashMap couldn't store primitives.

Upvotes: 0

MartinL
MartinL

Reputation: 3308

Proof:

when you run these Tests you'll get an AssertionError in second Test (because memory gets lower, even if you stop resetting memory-field). Once you try this tests with 10.000 loops you'll get at both StackOverflowError.

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import org.junit.Test;


public class TestRedundantIntegers {

    private long memory;

    @Test
    public void whenRecursiveIntIsSet() { 
        memory = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory(); 
        recurseInt(0, 100);
    } 

    private void recurseInt(int depth, int someInt) { 
        int x = someInt;

        assertThat(memory,is(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));
        memory=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory(); 
        if (depth < 1000) 
            recurseInt(depth + 1, x); 
    } 

    @Test
    public void whenRecursiveIntegerIsSet() { 
        memory = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory(); 
        recurseInteger(0, new Integer(100));
    } 

    private void recurseInteger(int depth, Integer someInt) { 
        Integer x = someInt;

        assertThat(memory,is(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));
        memory=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory(); 
        if (depth < 1000) 
            recurseInt(depth + 1, x); 
    } 
}

Upvotes: 0

xthexder
xthexder

Reputation: 1565

If you look at the source code of java.lang.Integer, the value is stored as an int.

private int value;

Your test is not valid, that's all there is to it.

Upvotes: 0

Michael McGowan
Michael McGowan

Reputation: 6608

The wrapper contains a primitive as a field, but it causes additional overhead because it's an object. The reference takes up space as well, but your example isn't really designed to show this.

The tests you designed aren't really well-suited for a precise measurement, but since you used them, try this example instead:

public static void main(String[] args) {
  int numInts = 100000;
  Integer[] array = new Integer[numInts];
//  int[] array = new int[numInts];
  for(int i = 0; i < numInts; i++){
    array[i] = i; //put some real data into the arrays using auto-boxing if needed
  }

  System.out.println("Used memory (bytes): " +   
  (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));
}

Now try it again but uncomment the primitive line and comment out the wrapper line. You should see that the wrapper takes up much more memory

Upvotes: 1

AusCBloke
AusCBloke

Reputation: 18532

For a start, an Integer wraps an int, therefore Integer has to be at least as big as int.

From the docs (I really doubt this is necessary):

The Integer class wraps a value of the primitive type int in an object. An object of type Integer contains a single field whose type is int.

So obviously a primitive int is still being used.

Not only that but objects have more overhead, and the most obvious one is that when you're using objects your variable contains a reference to it:

Integer obj = new Integer(100);
int prim = 100;

ie. obj stores a reference to an Integer object, which contains an int, whereas prim stores the value 100. That there's enough to prove that using Integer over int brings with it more overhead. And there's more overhead than just that.

Upvotes: 1

Daniel Lubarov
Daniel Lubarov

Reputation: 7924

I wouldn't pay attention to Runtime.freeMemory -- it's very ambiguous (does it include unused stack space? PermGen space? gaps between heap objects that are too small to be used?), and giving any precise measurement without halting all threads is impossible.

Integers are necessarily less space efficient than ints, because just the reference to the Integer takes 32 bits (64 for a 64-bit JVM without compressed pointers).

If you really want to test it empirically, have many threads recurse deeply and then wait. As in

class TestThread extends Thread {
    private void recurse(int depth) {
        int a, b, c, d, e, f, g;
        if (depth < 100)
            recurse(depth + 1);
        for (;;) try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {}
    }

    @Override public void run() {
        recurse(0);
    }

    public static void main(String[] _) {
        for (int i = 0; i < 500; ++i)
            new TestThread().start();
    }
}

Upvotes: 2

r0ast3d
r0ast3d

Reputation: 2635

http://www.javaspecialists.eu/archive/Issue193.html

This might help you understand/explore things a little bit more. An excellent article! Cheers!

Upvotes: 0

Tony Ren
Tony Ren

Reputation: 83

Your test case is too simple to be of any conclusive result.

Any test case that takes less than 5 seconds doesn't mean anything.

You need to at least do something with these objects you are creating. The JVM can simply look at your code and just not do anything because your objects aren't ever used, and you exit. (Can't say for certain what the JVM interpreter does, but the JIT will use escape analysis to optimize your entire testcase into nothing)

First of all, if you're looking for memory effectiveness, primitives are smaller because they are what size they are. The wrapper objects are objects, and need to be garbage collected. They have tons of fields within them that you can use, those fields are stored somewhere...

Primitives aren't "designed" to be more effective. Wrapper objects were designed to be more feature friendly. You need primitives, because how else are you going to store a number?

If you really wan't to see the memory difference, take a real application. If you want to write it yourself, go ahead but it'll take some time. Use some text editor and search and replace every single int declaration with Integer, and long with Long, etc. Then take a look at the memory footprint. I wouldn't be surprised if you see your computer explode.

From a programming point of view, you need to use primitives when necessary, and wrapper objects when necessary. When its applicable to do both, it's your preference. Trust me, there aren't that many.

Upvotes: 0

java_mouse
java_mouse

Reputation: 2109

Runtime.getRuntime().freeMemory() : getting delta on this does not give you the correct statistics as there are many moving parts like garbage collection and other threads.

Integer takes more memory than int primitive.

Upvotes: 0

xthexder
xthexder

Reputation: 1565

If your first example, you have the equivalent to 1 integer, and 2 pointers. Because Integer is an Object, it has pointer properties, and contains functions.

By using int instead of Integer, you are copying the value 3 times. You have a difference in 24 bytes, which is used for storing the headers and values of your extra 2 ints. Although I wouldn't trust your test: the JVM can be somewhat random, and it's garbage collection is quite dynamic. As far as required memory for a single Integer vs int, Integer will take up more space because it is an Object, and thus contains more information.

Upvotes: 0

Related Questions