Detailed Explanation of Time consuming Caused by Automatic Packing and Unpacking in Java

  • 2021-07-16 02:29:10
  • OfStack

What is automatic packing and unpacking

First, throw out the definition. When the basic data types in Java are operated with their wrapper classes, the compiler will automatically help us convert them. The conversion process is transparent to programmers, that is, packing and unpacking. Packing and unpacking can make our code simpler and easier to understand

Time consuming problem

Before talking about the automatic packing and unpacking of Java, let's look at an example.

I made this mistake in the project (embarrassment), take it out and encourage it!


private static long getCounterResult() {
 Long sum = 0L;
 final int length = Integer.MAX_VALUE;
 for (int i = 0; i < length; i++) {
 sum += i;
 }
 return sum;
}
public static void main(String[] args) {
 long startCountTime = System.currentTimeMillis();
 long result = getCounterResult();
 long endCountTime = System.currentTimeMillis();
 System.out.println("result = " + result + ", and take up time : " + (endCountTime - startCountTime) / 1000 + "s");
}

On my computer (macOS 64-bit system, higher configuration), the print results are as follows:

result = 2305843005992468481, and take up time : 12s

I actually used 12s, which is unbearable. How can normal code take so long? It will take longer to run on a computer with a configuration difference of 1 point (stunned. jpg).

We might as well read the following contents before analyzing and solving the above time-consuming problems.

Basic concepts

Automatic packing (Autoboxing) and automatic unpacking (AutoUnboxing) have been available since jdk 1.5.

Automatic boxing is the process that Java automatically converts the original (basic) type into the corresponding wrapper (object) type, such as converting int variables into Integer objects. This process is called boxing.

Automatic unpacking is the process that Java automatically converts wrapper (object) types into basic types, such as converting Integer objects into int type values. This process is called unpacking.

It is called automatic packing and unpacking because these operations are not manual (Cheng Xuyuan) operations, but a feature of Java.

The following table is the corresponding table of basic types and corresponding encapsulation types in Java:

基本类型 封装器类
int Integer
byte Byte
long Long
float float
double Double
char Character
boolean Boolean

Example of automatic packing:


int a = 3;
Integer b = a;

Example of automatic unpacking:


Integer b = new Integer(7);
int a = b;

Integer/int Automatic Unpacking and Packing

The following code is the valueOf method in the source code of Integer.


/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value. If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since 1.5
 */
public static Integer valueOf(int i) {
 //  If i Is greater than the value of -128 Less than 127 Returns the 1 Of the buffers 1 A Integer Object 
 if (i >= IntegerCache.low && i <= IntegerCache.high)
 return IntegerCache.cache[i + (-IntegerCache.low)];
 
 //  Otherwise return  new 1 A Integer  Object 
 return new Integer(i);
}

We are executing the following code, as follows:


Integer i = 100;

The above code is equivalent to the following code:


Integer i = Integer.valueOf(100);

Combined with the above source code, it can be seen that if the value is between [-128, 127] (double closed interval), the Integer object will not be recreated, but will be obtained directly from the cache (constant pool), and the data will be read much faster by obtaining from the constant pool instead of stack operation.

Let's look at a common basic interview question (please give printed results), as follows:


public static void main(String[] args) {
 // ⓵
 Integer a = new Integer(121);
 Integer b = new Integer(121);
 System.out.println(a == b);
 
 // ⓶
 Integer c = 121;
 Integer d = 121;
 System.out.println(c == d);
 
 // ⓷
 Integer e = 129;
 Integer f = 129;
 System.out.println(e == f);
 
 // ⓸
 int g = 50;
 Integer h = new Integer(50);
 System.out.println(g == h);
}

Analysis results:

: false, two objects are compared to point to different heap memory

: true, automatically packed with values between [-128, 127] (double closed interval)

: false, automatically packed and not between [-128, 127] (double closed interval)

: true, automatically unpacking and values between [-128, 127] (double closed interval)

Analytic time-consuming problem

Class Long also has a corresponding valueof method, the source code is as follows:


public static Long valueOf(long l) {
 final int offset = 128;
 if (l >= -128 && l <= 127) { // will cache
  return LongCache.cache[(int)l + offset];
 }
 return new Long(l);
}

This is very similar to Integer. The reason has been mentioned above, so I won't repeat it here.

In the opening example, the getCounterResult method has the following code, as follows:


Long sum = 0L;

Obviously, we declared an object sum of Long. Because of automatic boxing, this code has no syntax errors, and the compiler will certainly not report errors. The above code is equivalent to the following code:


Long sum = Long.valueof(0);

In the for loop, if it exceeds [-128, 127], new objects will be created, so it will take time to execute the program without stopping creating objects and applying for heap memory.

Modify the code under 1 as follows:


int a = 3;
Integer b = a;
0

The execution time is greatly shortened.

Summarize


Related articles: