integer 缓存池可扩容至 -128~200000,通过 -xx:autoboxcachemax=200000 实现;long 等类型缓存不可调,需用 concurrenthashmap 显式代理;验证用 jfr 或 -xx:+printclasshistogram,判等必须用 equals()。

Java 默认的包装类缓存池(如 IntegerCache、LongCache)仅覆盖 -128 到 127 范围,生产环境若频繁使用超大数值(如订单号、用户ID、时间戳等在 10000~1000000 区间),默认缓存无法生效,导致大量重复对象创建、GC 压力上升。定制超大缓存池并非修改源码,而是通过 JVM 参数、规范用法与轻量封装协同实现。
明确可定制的包装类与限制
只有 Integer 支持运行时扩展缓存上限;Long、Short、Byte、Character 的缓存范围在类加载时硬编码固定(如 LongCache.cache 长度恒为 256),不可动态调整;Boolean 固定为两个实例,Float/Double 无缓存机制。
关键依据来自 IntegerCache 源码中的静态块逻辑:
- 读取系统属性
java.lang.Integer.IntegerCache.high - 经
VM.getSavedProperty()获取配置值 - 最终赋值给
IntegerCache.high,影响cache[]数组大小
生产环境 Integer 缓存池扩容实操
在 JVM 启动参数中添加:
-XX:AutoBoxCacheMax=200000该参数等价于设置 java.lang.Integer.IntegerCache.high=200000,将缓存范围从默认 [-128, 127] 扩展至 [-128, 200000]。注意:
- 必须在应用启动前配置,类加载后
IntegerCache静态块已执行,不可再修改 - 内存占用 ≈
(200000 + 128 + 1) × (Integer 对象头 + value 字段),约增加 2~3 MB 堆外元空间(实际为堆内对象,但数量可控) - 避免设得过大(如 1000 万),否则初始化耗时长、GC 扫描压力陡增
规避 Long 等不可调包装类的缓存缺失
对 Long、Short 等无法扩展的类型,采用“显式缓存代理”模式:
- 定义线程安全的静态
ConcurrentHashMap<long long></long>,key/value 均为目标值 - 封装工具方法:
public static Long cachedLong(long v) { return CACHE.computeIfAbsent(v, Long::valueOf); } - 在核心路径(如 DAO 层 ID 封装、DTO 构建)统一调用该方法,替代直接赋值
Long l = 123456L - 配合 Guava 或 Caffeine 设置 LRU 驱逐策略,防止无限增长(例如最大 10 万条)
验证与避坑要点
缓存是否生效,不能只看 == 比较结果——这仅适用于同一 JVM 内且确认在缓存范围内。更可靠的方式是:
- 启用 JVM 参数
-XX:+PrintClassHistogram,观察java.lang.Integer实例数是否显著下降 - 用 JFR(Java Flight Recorder)录制内存分配事件,过滤
Integer.<init></init>调用频次 - 切记:所有比较一律用
.equals(),即使开启大缓存,也不能依赖==判等,因缓存未命中时仍会新建对象 - 禁止在循环中调用
new Integer(x),JDK 9+ 已标记为@Deprecated,且绕过缓存










