'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
intfield - 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 ofInteger. - If the
Integervalues mostly represent numbers in the range -128 to + 127, allocate them withInteger.valueOf(int). The JLS guarantees thatIntegerobjects created that way will be shared. (Note that when anIntegeris created by auto-boxing, then JLS stipulates thatvalueOfis used. So, in fact, this "fix" has already been applied in your example.) - If your
Integervalues mostly come from a larger but still small domain, consider implementing your own cache for sharingIntegerobjects.
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:
MyIntheader words - 8 bytesMyInt.bytesfield - 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 |
