'Memory footprint of int[] and Integer[] arrays

I try to create an array of Integers (i tried with own object but the same happened with int) , with size of 30 million. i keep getting "OutOfMemoryError: Java heap space"

Integer [] index = new Integer[30000000];
for (int i = 0 ; i < 30000000 ; i++){
    index[i] = i;
}

i checked the total heap space, using "Runtime.getRuntime().totalMemory()" and "maxMemory()" and saw that i start with 64 MB and the max is 900+ MB, and during the run i get to 900+ on the heap and crush.

now i know that Integer takes 4 bytes, so even if i multiply 30*4*1000000 i should still only get about 150-100 mega.

if i try with a primitive type, like int, it works.

how could i fix it ?



Solution 1:[1]

Lets assume that we are talking about a 32bit OpenJDK-based JVM.

  • Each Integer object has 1 int field - occupying 4 bytes.
  • Each Integer object has 2 header words - occupying 8 bytes.
  • The granularity of allocation is (I believe) 2 words - 4 bytes of padding.
  • The Integer[] has 1 reference for each array element / position - 4 bytes.

So the total is 20 bytes per array element. 20 x 30 x 1,000,000 = 600,000,000 Mbytes. Now add the fact that the generational collector will allocate at least 3 object spaces of various sizes, and that could easily add up to 900+ Mbytes.


how could i fix it ?

  • Use int[] instead of Integer.
  • If the Integer values mostly represent numbers in the range -128 to + 127, allocate them with Integer.valueOf(int). The JLS guarantees that Integer objects created that way will be shared. (Note that when an Integer is created by auto-boxing, then JLS stipulates that valueOf is used. So, in fact, this "fix" has already been applied in your example.)
  • If your Integer values mostly come from a larger but still small domain, consider implementing your own cache for sharing Integer objects.

My question was about Integer as an example, in my program i use my own object that only holds an array of bytes (max size of 4). when i create it, it takes a lot more then 4 bytes on the memory.

Yes, it will do.

Let's assume your class is defined like this:

public class MyInt {
    private byte[] bytes = new byte[4];
}

Each MyInt will occupy:

  • MyInt header words - 8 bytes
  • MyInt.bytes field - 4 byte
  • Padding - 4 bytes
  • Header words for the byte array - 12 bytes
  • Array content - 4 bytes

Now add the space taken by the MyInt reference:

  • Reference to each MyInt - 4 bytes

Grand total - 36 bytes per MyInt element of a MyInt[].

Compare that with 20 bytes per Integer element of an Integer[] or 4 bytes per int element of an int[].


How to fix that case?

Well an array of 4 bytes contains 32 bits of data. That can be encoded as int. So the fix is the same as before. Use an int[] instead of a MyInt[], or (possibly) adapt one of the other ideas discussed above.

Alternatively, make the heap larger, or use a database or something like that so that the data doesn't need to be held in RAM.

Solution 2:[2]

Integer is an object which will take more than 4 bytes. How much more is implementation dependent. Do you really need Integer? The only benefit is that it can be null. Perhaps you could use a "sentinal value" instead; say, -1, or Integer.MIN_VALUE.

Solution 3:[3]

Perhaps you should be using a database rather than a huge array, but if you must use a huge array of objects, have you tried increasing the Java memory size by using a the -Xms command line argument when running the Java application launcher?

Solution 4:[4]

This is not what you are looking for but the optimal solution is to use a function instead of an array in this simple example.

static int index(int num) {
    return num;
}

If you have a more realistic example, there may be other optimisations you can use.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 dty
Solution 3 Hovercraft Full Of Eels
Solution 4 Peter Lawrey