存储0-9值:ArrayList<Integer>与ArrayList<String>哪个占用内存更多?
嘿,这个问题问得挺有意思,咱们从Java内存模型的角度拆解一下,答案其实很明确:存储0到9的数值时,ArrayList
先搞清楚ArrayList的本质
不管你存的是Integer还是String,ArrayList内部其实都是存的对象引用(64位JVM开启指针压缩的话,每个引用占4字节;没开的话是8字节)。这部分的开销两者几乎一致,真正的差异来自于这些引用指向的实际对象本身。
1. Integer对象的内存开销
0到9正好落在Integer的默认缓存池范围内(-128到127),所以当你用自动装箱(比如list.add(0))或者Integer.valueOf(0)时,JVM会直接复用提前创建好的缓存对象,不会新建实例。
单个缓存Integer对象的内存结构(以JDK8、指针压缩为例):
- 对象头:12字节(包括Mark Word、类指针)
- 内部的int字段:4字节
- 内存对齐到8字节的倍数,所以单个Integer对象占16字节
因为0-9每个数值对应一个缓存对象,所以10个Integer对象总共占10 * 16 = 160字节(当然,这些缓存对象是JVM启动时就存在的,严格来说不算ArrayList“额外”创建的,但如果算整个集合关联的内存,这部分要算进去)。
2. String对象的内存开销
同样,"0"到"9"这些字符串会被放入字符串常量池,复用已有实例,不会每次新建。但String的结构比Integer复杂得多:
以JDK8为例,单个单字符String(比如"0")的内存:
- String对象本身:
- 对象头:12字节
- char数组引用:4字节
- hash值字段:4字节
- offset偏移量:4字节
- count字符数量:4字节
- 总大小28字节,对齐到32字节
- 关联的char数组:
- 数组对象头:12字节
- 数组长度:4字节
- 单个char值:2字节
- 总大小18字节,对齐到24字节
所以单个String对象(含关联数组)的总开销是32 + 24 = 56字节,10个就是10 * 56 = 560字节——这比Integer的160字节大了好几倍。
额外补充:特殊情况
如果是手动创建新对象(比如new Integer(0)或new String("0")),那每个实例都是全新的,内存开销会更高,但这种场景在日常开发里很少见,因为自动装箱和直接字符串字面量都是默认复用缓存/常量池的。
总结
两者的ArrayList本身内存开销差不多,但因为String对象的结构复杂度远高于Integer,再加上每个String还绑定了一个字符数组,所以存储0-9时,ArrayList
内容的提问来源于stack exchange,提问作者Anuj

