Java中大量基于HashMap的对象引发高内存占用问题咨询
Java中大量基于HashMap的对象引发高内存占用问题咨询
嘿,兄弟,我来给你拆解下这个内存占用过高的问题,太有代表性了!
首先先把你没贴完的代码补全(咱都懂,有时候贴代码容易截断):
public class MemTest { public static void main(String[] args) { List<MyDataHolder_map> list = new LinkedList<>(); for (int i = 0; i < 50_000_000; i++) { if(i % 100_000==0) System.out.println(i); MyDataHolder_map d = new MyDataHolder_map(); d.add("key1", "value1"+i); d.add("key2", "value2"+i); d.add("key3", "value3"+i); d.add("key4", "value4"+i); d.add("key5", "value5"+i); d.add("key6", "value6"+i); list.add(d); } } } // 基于Map存储数据的实现 class MyDataHolder_map { private Map<String, String> data = new HashMap<>(); public void add(String key, String value) { data.put(key, value); } } // 基于成员变量存储数据的实现 class MyDataHolder_variable { private String key1; private String key2; private String key3; private String key4; private String key5; private String key6; public void setKey1(String key1) { this.key1 = key1; } // 其余key的setter方法同理 }
为啥基于HashMap的版本内存占用会这么夸张?
核心问题就是HashMap本身的内存开销远大于你实际要存储的数据量,尤其当你只存少量键值对的时候:
- 默认容量的空间浪费:默认的HashMap初始容量是16,哪怕你只存6个键值对,它内部的数组还是会占用16个槽位的空间,空槽位虽然存的是null,但数组结构本身就要占内存,这纯粹是浪费。
- HashMap的固定结构开销:每个HashMap实例都自带一堆额外字段——数组引用、size、modCount、加载因子、阈值等等,这些加起来是一笔不小的固定开销,你要创建5000万个这样的对象,这笔开销乘上5000万直接就炸了。
- Entry/Node的包装开销:HashMap里的每个键值对都要被包装成Entry(JDK8+是Node)对象,每个Entry除了key和value,还要存next指针处理哈希冲突,这又是每个键值对额外的内存占用,而成员变量版的Holder直接存String引用,完全没这层包装。
给你的优化方案
1. 优先用自定义成员变量的Holder类(最优解)
如果你的数据字段是固定的(就这6个key),那MyDataHolder_variable这种实现绝对是首选!每个对象只存6个String引用,没有任何额外的集合开销,内存占用会比HashMap版低至少70%以上,5000万个对象的话能省出几十GB的内存,效果立竿见影。
2. 非要用HashMap的话,手动指定初始容量
如果因为某些原因必须用HashMap(比如字段不固定),那一定要在初始化的时候指定准确的初始容量,把空间浪费降到最低:
private Map<String, String> data = new HashMap<>(6);
指定初始容量为6,HashMap会自动计算出刚好能容纳6个元素的内部数组大小,不会像默认那样用16的容量空占一堆位置。
3. 不可变数据用轻量Map实现
如果你的数据是不可变的,可以用JDK9+的Map.of()创建不可变Map,它的内部结构比普通HashMap紧凑得多,没有扩容逻辑,内存开销小很多:
// 初始化时直接构建不可变Map private Map<String, String> data = Map.of( "key1", "value1"+i, "key2", "value2"+i, "key3", "value3"+i, "key4", "value4"+i, "key5", "value5"+i, "key6", "value6"+i );
最后再提个醒
当你创建超大量对象的时候,对象的结构设计对内存的影响是决定性的,能不用集合存固定字段就别用,那纯粹是给内存添负担。
备注:内容来源于stack exchange,提问作者Bhuvan
相关产品推荐
相关产品推荐

