How many objects are created by using the Integer wrapper class?
Asked Answered
S

5

59
Integer i = 3; 
i = i + 1; 
Integer j = i; 
j = i + j; 

How many objects are created as a result of the statements in the sample code above and why? Is there any IDE in which we can see how many objects are created (maybe in a debug mode)?

Speedy answered 17/3, 2016 at 10:59 Comment(1)
AFAIK, any decent IDE with CPU and/or memory profiler should do; NetBeans comes to mind. Just execute profiling (note to enable profiling standard lib classes too!) and look at a) how many Integer object were created (by looking at the memory used etc. in memory profiler), b) how many times the Integer c-tor was called (by looking at the method execution counts in CPU profiler)Suppose
S
101

The answer, surprisingly, is zero.

All the Integers from -128 to +127 are pre-computed by the JVM.

Your code creates references to these existing objects.

Seven answered 17/3, 2016 at 11:3 Comment(7)
See Write a program that makes 2 + 2 = 5 for an example of how to access these existing objects (you really shouldn't) and manipulate them for comic/disastrous effect (you really really shouldn't).Estrange
@Estrange Thanks guys. I love you both.Is there any reference link for it?Speedy
@SyameshK docs.oracle.com/javase/7/docs/api/java/lang/… "This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range."Proviso
Is this specific to Oracle Java or must this be true for other implementations (like IBM) also?Mauer
@MartinSchröder it is required by the Java language specification docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7Dominate
@josefx: But: "The implementation may cache these, lazily or eagerly." (emphasis mine)Mauer
Does this goes with java5 as well?Speedy
N
60

The strictly correct answer is that the number of Integer objects created is indeterminate. It could be between 0 and 3, or 2561 or even more2, depending on

  • the Java platform3,
  • whether this is the first time that this code is executed, and
  • (potentially) whether other code that relies on boxing of int values runs before it4.

The Integer values for -128 to 127 are not strictly required to be precomputed. In fact, JLS 5.1.7 which specified the Boxing conversion says this:

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1) ... then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.

Two things to note:

  • The JLS only requires this for >>literals<<.
  • The JLS does not mandate eager caching of the values. Lazy caching also satisfies the JLS's behavioral requirements.

Even the javadoc for Integer.valueof(int) does not specify that the results are cached eagerly.

If we examine the Java SE source code for java.lang.Integer from Java 6 through 8, it is clear that the current Java SE implementation strategy is to precompute the values. However, for various reasons (see above) that is still not enough to allow us to give a definite answer to the "how many objects" question.


1 - It could be 256 if execution of the above code triggers class initialization for Integer in a version of Java where the cache is eagerly initialized during class initialization.

2 - It could be even more, if the cache is larger than the JVM spec requires. The cache size can be increased via a JVM option in some versions of Java.

3 - In addition to the platform's general approach to implementing boxing, a compiler could spot that some or all of the computation could be done at compile time or optimized it away entirely.

4 - Such code could trigger either lazy or eager initialization of the integer cache.

Neaten answered 17/3, 2016 at 11:43 Comment(10)
This is not the complete story. These Integer objects are precomputed in the class initializer of java.lang.Integer.IntegerCache but the initialization of that class is triggered by its first use so unless the JRE uses such boxed values itself before entering the main method (in my test it didn’t), the first boxing of a value inside that range will trigger the initialization. So it’s not correct to say that no Integer objects are created as in fact 256 Integer objects are created while executing the main method.Moke
@Moke - It is also not correct to say that the number is not zero because 1) we don't >>know<< that this code is in the main method, and 2) we don't >>know<< that the actual JVM implements the cache the same way as Java 6 through 8. Also, the number could be LARGER than 256.Neaten
Indeed, things can get even more complicated. I was specifically referring to the last part about the “current generation Oracle & OpenJDK Java SE JVMs”. As said in the comment that has been removed, HotSpot may also remove the boxing as it knows about it’s semantics and the question’s code does not depend on the identities of the Integer objects. Or it may elide the entire operation, if i and j are never used afterwards. A different JVM implementation could represent certain boxed values by storing int values inside of pointers to address ranges outside the heap without any objects…Moke
@Moke - It is theoretically possible that boxed values could be outside of the heap ... but implausible. Dealing with that possibility for every reference would an unwarranted GC overhead.Neaten
The overhead wouldn’t be necessarily big. E.g., the current 32 Bit JVMs don’t support heaps larger than 2GB, which implies that the highest bit of in-heap addresses is never set. So if off-heap references always have that bit set, you can easily test it, as it is identical to the sign bit and almost every CPU has an intrinsic test for it, most of them provide it even for free when loading the address into a CPU register. So you can combine the off-heap test with the null reference test, which you need anyway (if >0 traverse, otherwise it’s either null or off-heap)…Moke
The 31 bit limitation on heap size is only for 32bit Windows. For 32 bit Linux, the there are 3GB of virtual address space that is usable. And many people / applications use a 64 bit JVM. Besides, the concrete benefit of holding (say) a couple of hundred boxed values outside of the heap is ... minimal.Neaten
In the past, all memory with the highest bit set was dedicated kernel space, hence unusable for user code. Today, this has been lifted for 32Bit processes, but for compatibility reasons, the heap still has to reside in the lower 2GB space, that’s exactly the reason why 32Bit JVMs still can’t use more than 2GB for the heap, despite the most recent operating systems support up to 3GB user space. This applies to both, Windows and Linux, both os support 3GB user space, but Oracle’s 32 Bit JVMs don’t support heap sizes >2GB.Moke
"On 64-bit operating systems running the 32-bit VM, the max heap size can be higher, approaching 4G on many Solaris systems." - oracle.com/technetwork/java/…Neaten
In short, 32 bit Oracle JVMs on 64 bit platforms do support > 2G heaps, depending on the OS.Neaten
Let’s end with the conclusion that not every JVM would benefit from such an optimization, but that never was the premise. A 32 bit JVM that restricts its heap to the lower 2GB might use such a trick and the potentially saving of up to 2³¹ boxed values (which would otherwise consume up to 16GB of memory, considering the minimum object size of 8 bytes), could justify not using the other 1GB of memory for the heap. Note that this memory area still might hold non-heap resources like I/O buffers and the metaspace. And on a lot of system’s, native code lies in the same address space as the data.Moke
R
17

First of all: The answer you are looking for is 0, as others already mentioned.

But let's go a bit deeper. As Stephen menthioned it depends on the time you execute it. Because the cache is actually lazy initialized.

If you look at the documentation of java.lang.Integer.IntegerCache:

The cache is initialized on first usage.

This means that if it is the first time you call any Integer you actually create:

  • 256 Integer Objects (or more: see below)
  • 1 Object for the Array to store the Integers
  • Let's ignore the Objects needed for Store the Class (and Methods / Fields). They are anyway stored in the metaspace.

From the second time on you call them, you create 0 Objects.


Things get more funny once you make the numbers a bit higher. E.g. by the following example:

Integer i = 1500; 

Valid options here are: 0, 1 or any number between 1629 to 2147483776 (this time only counting the created Integer-values. Why? The answer is given in the next sentence of Integer-Cache definition:

The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option.

So you actually can vary the size of the cache which is implemented.

Which means you can reach for above line:

  • 1: new Object if your cache is smaller than 1500
  • 0: new Objects if your cache has been initialized before and contains 1500
  • 1629: new (Integer) - Objects if your cache is set to exactly 1500 and has not been initialized yet. Then Integer-values from -128 to 1500 will be created.
  • As in the sentence above you reach any amount of integer Objects here up to: Integer.MAX_VALUE + 129, which is the mentioned: 2147483776.

Keep in mind: This is only guaranteed on Oracle / Open JDK (i checked Version 7 and 8)

As you can see the completely correct answer is not so easy to get. But just saying 0 will make people happy.


PS: using the menthoned parameter can make the following statement true: Integer.valueOf(1500) == 1500

Referee answered 17/3, 2016 at 20:8 Comment(0)
S
5

The compiler unboxes the Integer objects to ints to do arithmetic with them by calling intValue() on them, and it calls Integer.valueOf to box the int results when they are assigned to Integer variables, so your example is equivalent to:

Integer i = Integer.valueOf(3);
i = Integer.valueOf(i.intValue() + 1);
Integer j = i;
j = Integer.valueOf(i.intValue() + j.intValue());

The assignment j = i; is a completely normal object reference assignment which creates no new objects. It does no boxing or unboxing, and doesn't need to as Integer objects are immutable.

The valueOf method is allowed to cache objects and return the same instance each time for a particular number. It is required to cache ints −128 through +127. For your starting number of i = 3, all the numbers are small and guaranteed to be cached, so the number of objects that need to be created is 0. Strictly speaking, valueOf is allowed to cache instances lazily rather than having them all pre-generated, so the example might still create objects the first time, but if the code is run repeatedly during a program the number of objects created each time on average approaches 0.

What if you start with a larger number whose instances will not be cached (e.g., i = 300)? Then each valueOf call must create one new Integer object, and the total number of objects created each time is 3.

(Or, maybe it's still zero, or maybe it's millions. Remember that compilers and virtual machines are allowed to rewrite code for performance or implementation reasons, so long as its behavior is not otherwise changed. So it could delete the above code entirely if you don't use the result. Or if you try to print j, it could realize that j will always end up with the same constant value after the above snippet, and thus do all the arithmetic at compile time, and print a constant value. The actual amount of work done behind the scenes to run your code is always an implementation detail.)

Sattler answered 18/3, 2016 at 6:55 Comment(0)
N
2

You can debug the Integer.valueOf(int i) method to find out it by yourself. This method is called by the autoboxing process by the compiler.

Noun answered 17/3, 2016 at 11:1 Comment(1)
This is not a good approach to finding the answer. It only tells you what happens on a specific execution platform. Other platforms could give you different results.Neaten

© 2022 - 2024 — McMap. All rights reserved.