【翻译】Integer Cache In Java(在Java中的Integer缓存机制)

This Java article is to introduce and discuss about Integer Cache. 

这篇Java文章将介绍和讨论整数缓存。

This is a feature introduced in Java 5 to save memory and improve the performance.

这是Java 5中引入的一个特性,用于节省内存和提高性能。

Let us first have a look at a sample code which uses Integers and showcases the Integer Cache behavior.

让我们首先来看一个使用整数并展示整数缓存行为的示例代码。

From there lets study how and why it is implemented. 

从那里让我们研究如何和为什么它被实现。

Can you guess the output of the following Java program.?

你能猜出下列Java程序的输出吗?

Obviously there is some twist in it and that’s why we have this Java article.

显然,这其中有一些曲折,这就是为什么我们要写这篇Java文章。

 1 package com.javapapers.java;
 2 
 3 public class JavaIntegerCache {
 4     public static void main(String... strings) {
 5 
 6         Integer integer1 = 3;
 7         Integer integer2 = 3;
 8 
 9         if (integer1 == integer2)
10             System.out.println("integer1 == integer2");
11         else
12             System.out.println("integer1 != integer2");
13 
14         Integer integer3 = 300;
15         Integer integer4 = 300;
16         
17         if (integer3 == integer4)
18             System.out.println("integer3 == integer4");
19         else
20             System.out.println("integer3 != integer4");
21                 
22     }
23 }

What we generally expect is to have both statements to return false. 

我们通常期望的是两个语句都返回false。

Though the values are same, the compared objects should be different as they will have different references.

虽然值是相同的,但是比较的对象应该是不同的,因为它们有不同的引用。

If you are a beginner, then in Java == checks for object references and equals() checks for values. 

如果您是初学者,那么在Java中==检查对象引用,而equals()检查值。

So here in this case, different objects should be having different reference and so when compared, they should return a false boolean value. 

在这种情况下,不同的对象应该有不同的引用所以当比较时,它们应该返回一个假布尔值。

What is strange here is, the behavior is not same. 

奇怪的是,这里的行为是不一样的。

Two similar if-conditions returns different boolean values.

两个相似的if条件返回不同的布尔值。

Now lets look at the above Java program’s output,

现在让我们看看上面的Java程序的输出,

integer1 == integer2
integer3 != integer4

Java Integer Cache Implementation(Java整数缓存实现)
In Java 5, a new feature was introduced to save the memory and improve performance for Integer type objects handlings. 

在Java 5中,引入了一个新特性来节省内存并提高整数类型对象处理的性能。

Integer objects are cached internally and reused via the same referenced objects.

整数对象在内部缓存,并通过相同的引用对象重用。

This is applicable for Integer values in range between –127 to +127 (Max Integer value).

这适用于-127到+127(最大整数值)范围内的整数值。

This Integer caching works only on autoboxing. 

此整数缓存仅在自动装箱上有效。

Integer objects will not be cached when they are built using the constructor.

当使用构造函数构建整数对象时,它们不会被缓存。

Automatic conversion done by Java compiler from a primitive to its corresponding Java wrapper class type is called autoboxing. 

Java编译器将原语自动转换为相应的Java包装器类类型称为自动装箱。

This is equal to using the valueOf as follows,
这就等于使用下面的valueOf,

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

So now we know where this caching should be implemented in the Java JDK source.

现在我们知道在Java JDK源代码中应该在哪里实现缓存。

Lets look at the valueOf method source from Java JDK. 

让我们看看来自Java JDK的方法源代码的值。

Following is from Java JDK 1.8.0 build 25.

下面是来自Java JDK 1.8.0 build 25的代码。

 1 /**
 2 * Returns an {@code Integer} instance representing the specified
 3 * {@code int} value.  If a new {@code Integer} instance is not
 4 * required, this method should generally be used in preference to
 5 * the constructor {@link #Integer(int)}, as this method is likely
 6 * to yield significantly better space and time performance by
 7 * caching frequently requested values.
 8 * 返回一个{@code Integer}实例,表示指定的{@code int}值。如果不需要新的{@code Integer}实例,则通常应优先使用此方法,而不是构造函数{@link #Integer(int)},因为通过缓存频繁请求的值,此方法可能会产生更好的空间和时间性能。
 9 *
10 * This method will always cache values in the range -128 to 127,
11 * inclusive, and may cache other values outside of this range.
12 *
13 * 此方法将始终缓存-128到127(包括)范围内的值,并且可能缓存此范围之外的其他值。
14 * @param  i an {@code int} value.
15 * @return an {@code Integer} instance representing {@code i}.
16 * 返回一个表示{@code i}的{@code Integer}实例。
17 * @since  1.5
18 */
19 public static Integer valueOf(int i) {
20     if (i >= IntegerCache.low && i <= IntegerCache.high)  //static final int low = -128;    static final int high; int h = 127; h = Math.min(i,Integer.MAX_VALUE - (-low) -1);high = h;
21         return IntegerCache.cache[i + (-IntegerCache.low)];  //static final Integer cache[];
22         return new Integer(i);
23 }

 

 

 

  

There is a lookup to IntegerCache.

cache before constructing a new Integer instance.

Then there is a Java class taking care of the Integer caching.

有一个对IntegerCache的查找。
在构造一个新的整数实例之前进行缓存。
然后有一个Java类负责整数缓存。

IntegerCache Class(IntegerCache类)

IntegerCache is a private static inner class of Integer class. 

IntegerCache是Integer类的一个私有静态内部类。

Lets have a look at that class.

让我们看看那个类。

It is nicely documented in the JDK and gives most of the information.

它很好地记录在JDK中,并提供了大部分信息。

 1 /**
 2      * Cache to support the object identity semantics of autoboxing for values between
 3      * -128 and 127 (inclusive) as required by JLS.
 4      * 缓存以支持JLS要求的-128和127(包括)之间值的自动装箱的对象标识语义。
 5      *
 6      * The cache is initialized on first usage.  The size of the cache
 7      * may be controlled by the {@code -XX:AutoBoxCacheMax=} option.
 8      * During VM initialization, java.lang.Integer.IntegerCache.high property
 9      * may be set and saved in the private system properties in the
10      * sun.misc.VM class.
11      *缓存在第一次使用时初始化。缓存的大小可以由{@code -XX:AutoBoxCacheMax=}选项控制。在VM初始化期间,java.lang.Integer.IntegerCache.high可以在sun.misc.VM类的私有系统属性中设置和保存属性。
12      */
13 
14     private static class IntegerCache {
15         static final int low = -128;
16         static final int high;
17         static final Integer cache[];
18 
19         static {
20             // high value may be configured by property
21             int h = 127;
22             String integerCacheHighPropValue =
23                 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
24             if (integerCacheHighPropValue != null) {
25                 try {
26                     int i = parseInt(integerCacheHighPropValue);
27                     i = Math.max(i, 127);
28                     // Maximum array size is Integer.MAX_VALUE
29                     h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
30                 } catch( NumberFormatException nfe) {
31                     // If the property cannot be parsed into an int, ignore it.
32                 }
33             }
34             high = h;
35 
36             cache = new Integer[(high - low) + 1];
37             int j = low;
38             for(int k = 0; k < cache.length; k++)
39                 cache[k] = new Integer(j++);
40 
41             // range [-128, 127] must be interned (JLS7 5.1.7)
42             assert IntegerCache.high >= 127;
43         }
44 
45         private IntegerCache() {}
46     }
47 The Javadoc 

 

The Javadoc comment clearly states that this class is for cache and to support the autoboxing of values between 128 and 127. 

The high value of 127 can be modified by using a VM argument -XX:AutoBoxCacheMax=size. 

So the caching happens in the for-loop.

It just runs from the low to high and creates as many Integer instances and stores in an Integer array named cache.

As simple as that. 

This caching is doing at the first usage of the Integer class. 

Henceforth, these cached instances are used instead of creating a new instance (during autoboxing).

Javadoc注释明确说明该类用于缓存并支持128到127之间的值的自动装箱。

可以使用VM参数-XX:AutoBoxCacheMax=size修改127的高值。

缓存发生在for循环中。

它只是从低到高运行,并创建尽可能多的整数实例,并存储在一个名为cache的整数数组中。

就这么简单。

这种缓存是在第一次使用Integer类时进行的。

此后,将使用这些缓存的实例而不是创建新实例(在自动装箱期间)。
Actually when this feature was first introduced in Java 5, the range was fixed to –127 to +127. 

Later in Java 6, the high end of the range was mapped to java.lang.Integer.IntegerCache.

high and a VM argument allowed us to set the high number. 

Which has given flexibility to tune the performance according to our application use case. 

What is should have been the reason behind choosing this range of numbers from –127 to 127. 

This is conceived to be the widely most range of integer numbers. 

The first usage of Integer in a program has to take that extra amount of time to cache the instances. 

实际上,在Java 5中首次引入该特性时,范围被固定为-127到+127。

后来在Java 6中,这个范围的高端被映射到Java .lang. integer . integercache。

high和VM参数允许我们设置高值。

这为根据我们的应用程序用例调整性能提供了灵活性。

选择-127到127这个范围的原因应该是什么。

这被认为是最广泛的整数范围。

在程序中第一次使用Integer必须花费额外的时间来缓存实例。

Cache Enforcement in Java Language Specification(Java语言规范中的缓存实施)
In the Boxing Conversion section of Java Language Specification (JLS) it is stated as follows,
在Java语言规范(JLS)的装箱转换部分中,声明如下:
If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between ‘\u0000’ and ‘\u007f’ inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. 

如果值p盒装是一个int类型的整数文字在-128年和127年之间包容(§3.10.1),或布尔文字真或假(§3.10.3),或一个字符之间的文字‘\ u0000’和‘\ u007f包容性(§3.10.4),然后让a和b p的任意两个拳击转换的结果。

It is always the case that a == b.

a == b总是这样。

A above statement ensures that the reference of objects with values between -128 and 127 should be the same. 

Reasoning for this decision is also provided as below,

Ideally, boxing a primitive value would always yield an identical reference. 

In practice, this may not be feasible using existing implementation techniques. 

The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects.

The implementation may cache these, lazily or eagerly. 

For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer’s part.

This allows (but does not require) sharing of some or all of these references. 

Notice that integer literals of type long are allowed, but not required, to be shared.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. 

Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

上面的语句确保值在-128和127之间的对象的引用应该是相同的。

该决定的理由如下:
理想情况下,装箱一个原始值总是会产生一个相同的引用。

在实践中,使用现有的实现技术可能不可行。

上面的规则是一种实用的折衷,要求某些公共值总是被包装成不可分辨的对象。

实现可以惰性地或急切地缓存它们。

对于其他值,规则不允许对程序员方面的装箱值的标识进行任何假设。

这允许(但不要求)共享部分或所有这些引用。

注意,允许共享long类型的整数字面值,但不是必需的。
这确保了在大多数情况下,行为将是期望的,而不会造成不适当的性能损失,特别是在小型设备上。

例如,内存限制较少的实现可以缓存所有char和short值,以及int和long值,范围在-32K到+32K之间。

Other Cached Objects(其他缓存对象)
This caching behavior is not only applicable for Integer objects. 

We have similar caching implementation for all the integer type classes.

这种缓存行为不仅适用于整数对象。

对于所有整数类型的类,我们都有类似的缓存实现。

We have ByteCache doing the caching for Byte objects.
We have ShortCache doing the caching for Short objects.
We have LongCache doing the caching for Long objects.
We have CharacterCache doing the caching for Character objects.
Byte, Short, Long has fixed range for caching, i.e. values between –127 to 127 (inclusive).

For Character, the range is from 0 to 127 (inclusive). 

Range cannot be modified via argument but for Integer, it can be done.

ByteCache对Byte对象进行缓存。

我们有ShortCache来缓存短对象。

我们让LongCache对长对象进行缓存。

我们让CharacterCache为Character对象做缓存。

字节,短,长有固定的缓存范围,即值之间-127到127(包括)。

对于字符,范围从0到127(包括)。

范围不能通过参数修改,但对于整数,可以这样做。


 文章翻译自:Java Integer Cache

 

posted @ 2020-04-10 23:09  厸清扬  阅读(348)  评论(0编辑  收藏  举报