zoukankan      html  css  js  c++  java
  • Java自动装箱中的缓存原理

    今天看到一道'经典'面试题:

            Integer a = 100;
            Integer b = 100;
            System.out.println(a==b);
            Integer a2 = 200;
            Integer b2 = 200;
            System.out.println(a2==b2);

    答案运行一下就能很容易的得出:true,false.

    这个题很'经典',之前也看过讲解,大体上说由于jdk的优化,存在一个缓存机制导致,但是一直没有自己去看过源码,今天正好又遇到了,就仔细的看了一下源码.

    以Integer为例,JDK中的关键代码:

     /**
         * 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() {}
        }

    从方法上的注释可以知道,JLS(Java语言规范)中定义了当处于-127-127之间的值时需要采用缓存机制,Oracle官网的原文如下:

    If the value p being boxed is true, false, a byte, or a char in the range u0000 to u007f, or an int or short number between -128 and 127 (inclusive), 
    then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

    原文链接: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7 

    当第一次调用这个缓存类的时候会初始化这个缓存, 从代码中很清楚的看到其实它就是直接初始化了一个数组,然后一口气将上下限之间对应的包装类都创建出来.且这个上限值

    还可通过JVM参数XX:AutoBoxCacheMax=<size>来设置.可以想象出有了这个缓存类后,每次调用的时候只要在这个区间内的都可以不用再创建包装类,直接从缓存中取出来即可,

    这个用法有点像String的常量池.装箱的源码如下:

        /**
         * 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);
        }

    再回过头来看一下那道面试题也就很清楚原因了,一个是使用到了这个缓存,另一个由于超出默认范围,所以直接调用的构造方法创建的新对象.

    明白了这个缓存机制后,其实很多的时候我们担心的性能问题就根本不存在了,因为大多数情况下这个装箱都是走的缓存.但同时也要注意,当我们错误的使用==来判断2个包装类的

    值是否相等时,由于这个缓存机制的存在,可能导致错误极难被发现,或是随机产生错误判断.

  • 相关阅读:
    解决xcode5升级后,Undefined symbols for architecture arm64:问题
    第8章 Foundation Kit介绍
    app 之间发送文件 ios
    iphone怎么检测屏幕是否被点亮 (用UIApplication的Delegate)
    CRM下载对象一直处于Wait状态的原因
    错误消息Customer classification does not exist when downloading
    How to resolve error message Distribution channel is not allowed for sales
    ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX这些东东是什么鬼
    有了Debug权限就能干坏事?小心了,你的一举一动尽在系统监控中
    SAP GUI和Windows注册表
  • 原文地址:https://www.cnblogs.com/chyu/p/8401841.html
Copyright © 2011-2022 走看看