Integer类缓存机制

问题:

Java的Integer类内部实现了一个静态缓存池,用于存储特定范围内的整数值对应的Integer对象。默认情况下,这个范围是-128至127。当通过lnteger.valueOf(int)方法创建一个在这个范围内的整数对象时,并不会每次都生成新的对象实例,而是复用缓存中的现有对象,会直接从内存中取出,不需要新建个对象。

实践:

java 复制代码
public class Test {
    public static void main(String[] args) {

        Integer a = Integer.valueOf(1);
        Integer b = Integer.valueOf(1);
        System.out.println(a==b);;

    }
}

源码:

java 复制代码
  private static class IntegerCache {
            //整体的思路就是 
            //1.valueof或者自动装箱调用该类的静态代码块
            //2.可以通过jvm设定最大值,也可以不设定
            //3.设定好最大值,计算范围,生成新的数组赋值给归档文件,
            //4.最后再赋值给cache缓存


        //缓存的下界,默认值为 -128,固定不可修改
        static final int low = -128;
        //缓存的上界,默认值为 127,但可以通过 JVM 参数动态调整
        //java -Djava.lang.Integer.IntegerCache.high
        static final int high;


        //缓存数组,存储从 low 到 high 范围
        //这个数组就是缓存机制的核心
        static final Integer[] cache;



        //一个额外的缓存数组,用于支持 Java 的 Class Data Sharing (CDS) 功能。
        //CDS 是一种优化技术,允许将共享的类数据(如缓存池)保存到归档文件中,从而加速 JVM 启动。
        //archivedCache就是归档缓存
        static Integer[] archivedCache;

        //静态代码块在类加载时执行,负责初始化缓存池。
        //IntegerCache 的 static 块会在第一次调用 Integer.valueOf(int) 或使用自动装箱时触发,也就说会触发缓存池
        static {
            // high value may be configured by property
            // 上界可以通过配置这个属性
            int h = 127;//此时配置的上界是127


            //你可以通过java -Djava.lang.Integer.IntegerCache.high=设置最高值
            //java -Djava.lang.Integer.IntegerCache.high=256里设置为256
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");


            //integerCacheHighPropValue 就是你设置的值
            //如果integerCacheHighPropValue不为空
            if (integerCacheHighPropValue != null) {
                try {
                    //1.integerCacheHighPropValue转换成int值
                    //2.比较 默认的127的和你设置的值,取最大
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    /

                    /* 
                    Integer.MAX_VALUE 是 Java 中 int 类型的最大值,等于 2^31 - 1,即 2147483647。它表示 int 类型能够存储的最大正整数。

                    low 是缓存池的下界,默认值为 -128。
                    (-low) 表示下界的绝对值,即 128。

                    Integer.MAX_VALUE - (-low)
                    这部分计算了从 low 到 Integer.MAX_VALUE 的整数个数。
                    公式:Integer.MAX_VALUE - (-low) 等价于 Integer.MAX_VALUE + low。

                    Integer.MAX_VALUE - (-low) - 1
                    减去 1 是为了确保数组的长度不会超出 Integer.MAX_VALUE。
                    数组的长度由 (high - low) + 1 决定,因此需要限制 high 的最大值。
                    */

                    //这个就是保证h在合法int范围内
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                    //如果这个属性不能被解析为整数,忽略它
                }
            }
            //赋值给high
            high = h;

            // Load IntegerCache.archivedCache from archive, if possible
            //从归档文件中加载缓存,如果存在的话
            CDS.initializeFromArchive(IntegerCache.class);
                
            // 计算容量
            // high - low = 127 - (-128) = 255
            // + 1是因为要算上边界 
            // eg.6 - 1 = 5, 但是之间这是之间差5个数 
            // 如果 把左边界1算上,那就是 1 2 3 4 5
            // 那还少一个6,所以要加1
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            //从归档文件里查找如果没有该缓存或者是所需容量的size>大于缓存的长度
            //就创建一个新的数组
            if (archivedCache == null || size > archivedCache.length) {
                //创一个size大小的数组
                Integer[] c = new Integer[size];
                //j=-128
                int j = low;
                //-128一直自增到c.length 也就是256
                //但是是加到255就停止,因为i < c.length而不是等于 i < 256
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                //把新生成的数组给归档文件
                archivedCache = c;
            }
            //再给cache,到这里就完成了缓存
            cache = archivedCache;
            //确保IntegerCache.high的值至少为127,即保证了缓存至少包含从-128到127的所有整数值,确保合理范围
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        //这是一个静态类,不需要实例化,所以需要私有
        private IntegerCache() {}
    }

归档文件

归档文件是一个特殊的文件,通常命名为 classes.jsa(Java Shared Archive),用于存储以下内容:

  • 类元数据:如类的结构信息。
  • 常量池:如字符串常量、方法引用等。
  • 缓存池 :如 IntegerCache 的缓存数组。

它的主要目的是:

  1. 加速 JVM 启动:通过预加载常用类的数据,减少类加载的时间。
  2. 节省内存:多个 JVM 实例可以共享同一个归档文件,避免重复加载相同的类数据。

归档文件的内容

归档文件中存储了以下类型的数据:

(1) 类元数据
  • 类的结构信息,包括类的字段、方法、继承关系等。
  • 这些数据在 JVM 加载类时会被直接使用,避免重新解析 .class 文件。
(2) 常量池
  • 常量池中存储了类中的常量数据,例如:
    • 字符串常量(如 "Hello")。
    • 方法引用、字段引用等符号引用。
  • 这些数据可以直接从归档文件中读取,而无需重新解析。
(3) 缓存池
  • 某些类(如 IntegerCache)的缓存数据也会被存储到归档文件中。
  • 例如,IntegerCache 的缓存数组(archivedCache)可以从归档文件中加载,避免每次运行时重新创建。
相关推荐
Armyyyyy丶6 小时前
Redis底层实现原理之五大基础结构
数据结构·redis·缓存
Volunteer Technology8 小时前
三高项目-缓存设计
java·spring·缓存·高并发·高可用·高数据量
2302_8097983212 小时前
【Redis】缓存的穿透、击穿和雪崩
数据库·redis·缓存
Listen-Y12 小时前
设计艺术~缓存结构设计
缓存
叫我阿柒啊13 小时前
从Java全栈到前端框架的全面实战:一次真实面试的深度解析
java·spring boot·缓存·微服务·消息队列·vue3·rest api
麦兜*15 小时前
MongoDB 性能调优:十大实战经验总结 详细介绍
数据库·spring boot·mongodb·spring cloud·缓存·硬件架构
CHANG_THE_WORLD15 小时前
C++ 并发编程指南 实现无锁队列
开发语言·c++·缓存·无锁队列·无锁编程
egoist202317 小时前
[linux仓库]性能加速的隐形引擎:深度解析Linux文件IO中的缓冲区奥秘
linux·运维·开发语言·缓存·缓冲区
失散131 天前
并发编程——17 CPU缓存架构详解&高性能内存队列Disruptor实战
java·缓存·架构·并发编程
郭俊强1 天前
nestjs 缓存配置及防抖拦截器
缓存·nestjs·防抖