`

翻译: 深入理解Java Integer的缓存策略

 
阅读更多
本文将介绍 Java 中 Integer 缓存的相关知识。这是 Java 5 中引入的一个有助于节省内存、提高性能的特性。
首先看一个使用 Integer 的示例代码,展示了 Integer 的缓存行为。接着我们将学习这种实现的原因和目的。
你可以先猜猜下面 Java 程序的输出结果。很明显,这里有一些小陷阱,这也是我们写这篇文章的原因。

/**
* 测试Integer的缓存 IntegerCache.cache
*/ 
private static void testIntegerCache() { 
    System.out.println("---int---"); 
    int a = 127, b = 127; 
    System.out.println(a == b);         //true 
    a = 128; 
    b = 128; 
    System.out.println(a == b);         //true 
 
    System.out.println("---Integer---"); 
    Integer aa = 127, bb = 127; 
    System.out.println(aa == bb);       //true 
    aa = 128; 
    bb = 128; 
    System.out.println(aa == bb);       //false 
    System.out.println(aa.equals(bb));  //true 

执行结果就如同上面的那样,我就不贴图来展示啦,我把原文的例子给换成自己的了。
在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。

上面的规则适用于整数区间 -128 到 +127。

这种 Integer 缓存策略仅在自动装箱(autoboxing)的时候有用,使用构造器创建的 Integer 对象不能被缓存。

Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

现在我们知道了 JDK 源码中对应实现的部分在哪里了。我们来看看 valueOf 的源码。下面是
JDK 1.8.0 build 25 中的代码。

/**
* 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 >= IntegerCache.low && i <= IntegerCache.high) 
        return IntegerCache.cache[i + (-IntegerCache.low)]; 
    return new Integer(i); 

在创建新的 Integer 对象之前会先在 IntegerCache.cache (是个Integer类型的数组)中查找。有一个专门的 Java 类来负责 Integer 的缓存。

IntegerCache 类

IntegerCache 是 Integer 类中一个私有的静态类。我们来看看这个类,有比较详细的文档,可以提供我们很多信息。

/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage.  The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/ 
 
private static class IntegerCache { 
    static final int low = -128; 
    static final int high; 
    static final Integer cache[]; 
 
    static { 
        // high value may be configured by property 
        int h = 127; 
        String integerCacheHighPropValue = 
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 
        if (integerCacheHighPropValue != null) { 
            try { 
                int i = parseInt(integerCacheHighPropValue); 
                i = Math.max(i, 127); 
                // Maximum array size is Integer.MAX_VALUE 
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 
            } catch( NumberFormatException nfe) { 
                // If the property cannot be parsed into an int, ignore it. 
            } 
        } 
        high = h; 
 
        cache = new Integer[(high - low) + 1]; 
        int j = low; 
        for(int k = 0; k < cache.length; k++) 
            cache[k] = new Integer(j++); 
 
        // range [-128, 127] must be interned (JLS7 5.1.7) 
        assert IntegerCache.high >= 127; 
    } 
 
    private IntegerCache() {} 


Javadoc 详细的说明这个类是用来实现缓存支持,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。 缓存通过一个 for 循环实现。从小到大的创建尽可能多的整数并存储在一个名为 cache 的整数数组中。这个缓存会在 Integer 类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。

实际上在 Java 5 中引入这个特性的时候,范围是固定的 -128 至 +127。后来在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的。 在程序中第一次使用 Integer 的时候也需要一定的额外时间来初始化这个缓存。

Java 语言规范中的缓存行为

在 Boxing Conversion 部分的Java语言规范(JLS)规定如下:
如果一个变量 p 的值属于:-128至127之间的整数(§3.10.1这个估计是版本号吧),true 和 false的布尔值 (§3.10.3),’u0000′ 至 ‘u007f’ 之间的字符(§3.10.4)中时,将 p 包装成 a 和 b 两个对象时,可以直接使用 a == b 判断 a 和 b 的值是否相等。

其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。

原文:http://javapapers.com/java/java-integer-cache/
分享到:
评论

相关推荐

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

     作者以易于理解的方式深入揭示了java虚拟机的内部工作原理,深入理解这些内容,将对读者更快速地编写更高效的程序大有裨益!  本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行...

    从 Java 代码到 Java 堆 理解和优化您的应用程序的内存使用

    【标题】:深入理解Java内存使用与优化:从代码到Java堆 【描述】:本文旨在帮助Java开发者深入了解从编写代码到Java堆的内存管理过程,以便更好地优化应用程序的内存使用。通过分析Java代码中的内存开销,以及讨论...

    java entity

    在实际开发中,还需要考虑数据的级联操作(CascadeType)、懒加载(Lazy Fetching)以及缓存策略等高级特性。同时,为了保持数据一致性,还需要理解并合理使用`@PrePersist`, `@PostPersist`, `@PreUpdate`, `@Post...

    JAVA常见异常BUG

    ### JAVA常见异常BUG详解 #### 一、Java.lang....开发者应该深入理解这些异常的原因,并采取有效措施来预防它们的发生。在实际开发过程中,良好的编码习惯和严格的测试流程对于减少这类异常至关重要。

    第7讲 int和Integer有什么区别1

    查看`Integer`的源码可以帮助我们更深入地理解其内部机制,比如`Integer.valueOf()`方法如何实现值缓存,以及`Integer`对象的比较操作是如何进行的。 6. **扩展讨论**: - 自动装箱/拆箱发生的时间:这些操作发生...

    Java 208道面试.docx

    Java 是一种广泛使用的编程语言,尤其在企业级应用和服务器端开发中占据主导地位。面试时,面试官通常会从多个方面考察候选...Java的面试涵盖范围广泛,深入理解每个领域并能灵活运用是成为优秀Java开发者的必备条件。

    200+道java基础题及答案.doc

    JDK(Java Development Kit)是Java开发工具包,它提供了Java开发和运行环境,包括JRE(Java Runtime Environment),以及用于编译Java源码的编译器Javac和其他调试工具。JRE仅提供运行Java程序所需的环境,如果...

    Java 一些值得注意的细节

    本文将深入探讨Java的一些值得注意的细节,帮助你避免常见陷阱,提升代码质量。 1. **自动装箱与拆箱**:Java中的`Integer`等包装类提供了自动装箱和拆箱功能,方便了开发者操作。但需要注意,虽然在基本类型和包装...

    《Java技术指南2019》

    该书分为基础篇、进阶篇、高级篇、架构篇和拓展篇五个部分,覆盖了Java编程的多个层面,包括Java虚拟机(JVM)的深入理解、Java基础语法、并发编程、网络编程以及最新的Java技术动态。书中还推荐了一系列的参考书籍...

    Java八股文高频面试题

    此外,面试题还可能涉及多线程的并发控制(如synchronized, volatile, Lock等)、集合框架(ArrayList, LinkedList, HashMap等的原理与使用)、SpringBoot框架的配置与使用、MySQL的索引优化、Redis的缓存策略以及...

    Java面试八股文2023最新版

    Java面试八股文是准备Java面试的关键资源,涵盖了广泛的Java技术领域,包括基础概念、框架、并发、JVM以及软技能。...准备面试时,不仅要掌握这些基础概念,还需要深入理解并能灵活应用到实际问题中。

    sqljet-1.1.6-sources.jar.zip

    4. **优化数据库操作**:通过源码,学习如何提高数据库读写性能,如批量操作、缓存策略等。 五、源码实践 实际开发中,你可以: 1. **扩展SQLJet功能**:根据需求,自定义SQLJet的行为,比如增加新的数据类型或函数...

    java performance

    4. **理解并发模型**:深入理解Java的并发模型(如volatile关键字的作用机制、原子操作的实现原理等),有助于更好地设计并行算法和数据结构。 ### 总结 通过对上述知识点的理解和实践,开发者可以在编写Java应用...

    BAT大厂2023年Java架构师岗面试题(综合版)

    Java 架构师在面试过程中会面临一系列深入且全面的问题,涵盖从基础知识到高级概念的广泛领域。以下是一些基于给定标题和描述的关键知识点详解: 1. **Java 语言特点**: - **简单易学**:Java 语法简洁,易于理解...

    java_sqr(big_int).rar_Big!_Java sqr_Java里面的sqr_java s_javasqr

    在Java编程语言中,处理大整数(Big Integer)是一项挑战,尤其是在进行高精度运算时。标题中的"java_sqr(big_int)"暗示我们要讨论的是如何在Java中对大整数执行平方根(square root)操作。这个压缩包中的"java_sqr...

    JAVA面试题及答案二百多道

    【Java基础】 1. JDK与JRE的区别: JDK(Java Development Kit)...以上仅是部分Java面试题及知识点的概述,每个话题都包含了大量的细节和实践技巧,深入学习和理解这些知识点对于成为一名优秀的Java开发者至关重要。

    Java面试.doc

    Redis的使用,如缓存策略、数据结构和操作命令。 **十六、JVM** 了解JVM内存模型,垃圾回收机制,性能调优等。 **十七、数据结构与算法** 熟练掌握链表、树、堆、图等数据结构,以及排序、搜索等基础算法,有助...

Global site tag (gtag.js) - Google Analytics