📜 ⬆️ ⬇️

Integer and int

In this topic, I want to describe some basic differences between primitive types and their corresponding object types using the example of int and Integer. These differences are quite simple and, if you think a little, they are quite logical, but, as experience has shown, the programmer does not always think about it.

The main difference, of course, is that Integer is a full-featured object that takes up space on the heap, and in the code you use links to it that are implicitly converted to values:
int a = 1000 ; // a -
Integer b = 1000 ; // b -
When assigning a value to a variable of type Integer, memory is usually allocated in the heap for a new object, as if you had written new Integer(1000) (the so-called autoboxing ). However, old objects are sometimes reused. This is illustrated by the following code (JDK 1.6):
Integer a1 = 50 ;
Integer a2 = 50 ;
Integer b1 = 500 ;
Integer b2 = 500 ;
System. out . println (a1==a2);
System. out . println (b1==b2);
The result of the execution will be:
true
false
Here, the static method java.lang.Integer.valueOf (int) is actually called, which, as you can see in the source , caches values ​​from -128 to 127 (in a more recent implementation, the upper boundary of the cache can be changed).

However, in most cases, a new object is created, and this can be significant. Remember also that the Integer object never changes its value. Consider this seemingly innocent code:
public class Increment
{
public static void main (String[] args)
{
Integer a= 0 ;
while ( true ) a++;
}
}
Let's copy the memory usage, for example, with the trial version of JProfiler :

Obviously, with each increment, a new Integer object is created, and the old ones are then cleaned up by the garbage collector when they accumulate about a hundred thousand. Good system load for normal increment operation.
')
In general, it is clear that the Integer should be used only when it is indispensable. One such example is parameterized types (generics), for example, standard collections. But here we must be careful to use memory wisely. I will give a somewhat exaggerated example based on the problem I encountered in a real project. In some scientific analysis, it was necessary to associate with certain objects long sets of natural numbers. You can emulate this with the following code:
import java.util.*;

public class MapInteger
{
static Map<Integer, Set<Integer>> subSets = new HashMap<Integer, Set<Integer>>();

public static void put (Integer key, int value)
{
if (!subSets. containsKey (key)) subSets. put (key, new HashSet<Integer>());
subSets. get (key). add (value);
}

public static Collection<Integer> getRandomKeys ()
{
List<Integer> vals = new ArrayList<Integer>();
for ( int i= 0 ; i<( int )(Math. random ()* 500 ); i++)
{
vals. add (( int )(Math. random ()* 1000 ));
}
return vals;
}

public static void main (String[] args)
{
new Scanner(System. in ). nextLine ();
for (Integer i= 0 ; i< 100000 ; i++)
{
for (Integer key: getRandomKeys ())
put (key, i);
}
new Scanner(System. in ). nextLine ();
}
}
For each number from the first hundred thousand, we define a set of keys using getRandomKeys (in the real task, the keys, of course, were not accidental) and add the current number to the corresponding sets of subSets. The key type Integer is chosen to simplify the illustration; in general, it is not important. Here are the numbers of objects before the operation:


But after:


The forced launch of the garbage collector did not help much:


40 megabytes of memory eat whole numbers - this is sad. The reason lies in the prototype of the put method:
public static void put(Integer key, int value)
Due to the fact that the int type is used here, the values ​​of the variable i are automatically converted to int (unboxing) when passed to the method, and then newly converted to Integer (boxing), but a new object is created. Replace the int value in the prototype with Integer value and run the profiler again. At the beginning the picture is the same:


But at the end of significant differences:


And after garbage collection:


So, replacing one int with an Integer, you can save about 40% of the memory used. Note that in for(Integer i=0; i<100000; i++) also not by chance that Integer is used: we will write an int here, and the first correction will not help. We see that the rule to write int wherever you can not write Integer, does not always work: in each case, you need to think. Sometimes your own implementation of the integer cache can also be useful.

Source: https://habr.com/ru/post/104231/


All Articles