面试题答案
一键面试内存管理优化
- 连续内存分配:与
ArrayList
类似,自定义动态数组应使用连续的内存空间存储元素,这样在遍历和随机访问时具有高效性,缓存命中率高。例如,在C++ 中可使用std::vector
背后的机制,通过new
分配一块连续内存。 - 对象池复用:对于频繁创建和销毁元素对象的场景,可以实现对象池机制。当元素从动态数组中移除时,不立即释放对象,而是将其放入对象池,下次添加新元素时,优先从对象池获取对象,减少内存分配和垃圾回收的开销。这一点
ArrayList
没有类似机制。
扩容策略优化
- 初始容量设置:
ArrayList
默认初始容量为10。自定义动态数组可根据实际使用场景,提供一个更合理的默认初始容量。如果预先知道大概的数据规模,可设置合适的初始容量,避免频繁扩容。 - 扩容因子调整:
ArrayList
扩容时,新容量为旧容量的1.5倍。自定义动态数组可根据数据增长特点调整扩容因子。例如,如果数据增长较为平缓,可适当增大扩容因子,减少扩容次数;如果数据增长波动较大,可采用较小的扩容因子,避免过多的内存浪费。 - 分批扩容:在扩容时,不一次性分配新的全部容量,而是分批次分配,逐步增加容量。例如,先分配略大于当前所需的容量,后续根据实际需求再逐步扩容,这样可减少一次性内存分配失败的风险,并且在一定程度上降低内存碎片产生的可能性,这是
ArrayList
未采用的策略。
与ArrayList
底层逻辑对比
- 内存管理:
ArrayList
在Java堆上分配连续内存存储元素,依赖Java的垃圾回收机制处理内存释放。自定义动态数组如果在C++ 等语言实现,需手动管理内存释放,通过对象池机制可在某些场景下优化内存使用,这是ArrayList
不具备的。
- 扩容策略:
ArrayList
采用固定的1.5倍扩容因子,简单直接。自定义动态数组可灵活调整扩容因子和采用分批扩容策略,能更好适应不同数据增长模式,但实现相对复杂。在某些特定场景下,自定义的扩容策略可能比ArrayList
的固定扩容策略性能更优。