clear()更省内存(复用底层数组),new ArrayList()分配新数组并使旧对象待GC;但若曾存大量元素,clear()后需trimToSize()避免内存浪费。

Java里clear()和new ArrayList()到底谁更省内存
直接说结论:clear()不释放底层数组,只清空元素引用;new会分配新数组、触发旧对象进入GC队列——但是否真“更耗”得看场景。别无脑换new,尤其在循环复用集合时。
根本区别不在“清空动作”,而在“底层数组是否复用”。ArrayList的clear()只是把size设为0,并把原数组中索引0到size-1位置的引用置为null(避免内存泄漏),但数组本身还挂着,下次add()直接复用。
-
clear()后,capacity不变,size == 0,后续add()不触发扩容 -
new ArrayList()分配新数组(默认capacity=10),原ArrayList对象(含老数组)可被GC,但GC时机不确定 - 如果集合长期维持小容量(比如固定存3个元素),反复
new会导致短命对象堆积,可能加重Young GC压力
什么情况下clear()反而埋雷
不是所有集合都适合clear()复用。最典型的是:集合曾装过大量临时对象,之后又长期只存少量数据。
例如缓存解析结果的ArrayList,某次解析了10万条日志,clear()后只剩3条配置项——这时底层数组仍占着约10万×4字节(假设是Object[]),而你只需要3个槽位。
立即学习“Java免费学习笔记(深入)”;
- 现象:
clear()后memory profiler显示该对象占用内存远高于实际需要 - 原因:
ArrayList不自动缩容,trimToSize()要手动调 - 正确做法:
list.clear(); list.trimToSize();(注意:这会触发一次数组复制) - 替代方案:如果容量波动极大,考虑用
LinkedList(但注意随机访问慢)或按需new
HashMap的clear()和new HashMap()有啥不同
HashMap的clear()比ArrayList更“轻”:它只把桶数组每个位置设为null,不释放数组本身,也不重置threshold(扩容阈值)。所以如果之前put过大量键值对,clear()后首次put()仍可能触发扩容计算,但数组还在。
-
clear()后,size == 0,但table.length和threshold保持不变 -
new HashMap()用默认初始容量16、负载因子0.75,threshold = 12 - 若业务中Map大小稳定在几百,但某次突发写入10万键值对,之后
clear()却不new,后续操作可能长期浪费内存 - 没有类似
trimToSize()的API,只能new或用new HashMap(initialCapacity)控制起点
线程安全集合的clear()要注意什么
ConcurrentHashMap和CopyOnWriteArrayList的clear()行为和普通集合差异很大,误用容易引发性能问题或语义误解。
-
ConcurrentHashMap.clear()不是原子操作:它分段遍历并清空,期间其他线程仍可读/写部分桶——不保证“某一时刻全空” -
CopyOnWriteArrayList.clear()会创建一个全新空数组,原数组等待GC,**开销接近new**,且写操作锁整个列表 - 如果在高并发写场景下频繁
clear(),CopyOnWriteArrayList的复制成本会飙升,不如换成普通ArrayList+ 外部同步 - 永远别假设
ConcurrentHashMap.clear()后立刻对所有线程可见为空;如需强一致性,用compute()或加额外协调机制
真正关键的不是选clear还是new,而是想清楚:这个集合的生命周期、典型容量范围、是否跨线程共享、GC敏感度如何。很多“优化”其实是在替JVM做它本不该承担的决策。










