为何未超出ArrayList容量时add()仍会调用grow()?
问题:ArrayList指定初始容量后仍触发grow()?
编辑2:补充细节重述问题
我做了一段代码的性能分析,结果让我疑惑:
public class ProfilerTest { private static int loops = 1_000_000_000; private static int listSize = 10; public static void main(String[] args) { for (int i = 0; i < loops; i++) { var list = new ArrayList<Integer>(listSize); for (int j = 0; j < listSize; j++) { list.add(j); } assert list.size() == listSize; } } }
性能分析器显示add(Object)调用了grow()。我查看了所用JDK的源码,ArrayList.add(Object)会调用下面这个辅助方法:
private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; }
按逻辑来看,只有当元素数量s等于数组容量时才会触发grow()。但即使我把初始容量设为2*listSize,性能分析器仍然显示grow()被调用了。我到底忽略了什么?
原始问题
我通过性能分析发现,自己的某个方法偶尔会调用ArrayList.grow()——但实际上我是已知所需容量的,理论上不该触发扩容,不过不排除其他方法修改了容量的可能。
出于好奇我做了个基准测试(注:之前看错了数据,误把吞吐量当成耗时,已删除错误结论)。
我现在的疑问只剩:
- 当把ArrayList填充到其指定的精确容量时,Java真的会调用
grow()吗?还是这只是性能分析器的统计误差(比如子例程调用grow()时被错误统计到父调用方)?
下面是我用JMH做的基准测试代码:
@State(Scope.Benchmark) @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 1, time = 3) @Measurement(iterations = 3, time = 3) @Fork(value=2) public class PerformanceTest { private int size = 30; @Benchmark public ArrayList<Integer> MatchingCapacity() { var list = new ArrayList<Integer>(size); for (int i = 0; i < size; i++) { list.add(i); } return list; } @Benchmark public ArrayList<Integer> MismatchingCapacity() { var list = new ArrayList<Integer>(size-1); for (int i = 0; i < size; i++) { list.add(i); } return list; } @Benchmark public ArrayList<Integer> OversizedCapacity() { var list = new ArrayList<Integer>(size + size/2); for (int i = 0; i < size; i++) { list.add(i); } return list; } @Benchmark public ArrayList<Integer> DefaultCapacity() { var list = new ArrayList<Integer>(); for (int i = 0; i < size; i++) { list.add(i); } return list; } }
测试结果:
# JMH version: 1.35 # VM version: JDK 17.0.3.1, Java HotSpot(TM) 64-Bit Server VM, 17.0.3.1+2-LTS-6 size=3 PerformanceTest.DefaultCapacity thrpt 6 37681589.763 ± 10696982.725 ops/s PerformanceTest.MatchingCapacity thrpt 6 54285199.864 ± 20674575.714 ops/s PerformanceTest.MismatchingCapacity thrpt 6 21430358.674 ± 11202223.852 ops/s PerformanceTest.OversizedCapacity thrpt 6 50519838.911 ± 19575866.550 ops/s size=30 PerformanceTest.DefaultCapacity thrpt 6 4253362.573 ± 120027.530 ops/s PerformanceTest.MatchingCapacity thrpt 6 8071248.285 ± 5138133.875 ops/s PerformanceTest.MismatchingCapacity thrpt 6 5108706.433 ± 562235.033 ops/s PerformanceTest.OversizedCapacity thrpt 6 6867041.239 ± 5561825.025 ops/s size=300 PerformanceTest.DefaultCapacity thrpt 6 466885.040 ± 486083.752 ops/s PerformanceTest.MatchingCapacity thrpt 6 693234.753 ± 268499.890 ops/s PerformanceTest.MismatchingCapacity thrpt 6 644182.306 ± 324785.510 ops/s PerformanceTest.OversizedCapacity thrpt 6 773775.315 ± 26808.161 ops/s size=3000 PerformanceTest.DefaultCapacity thrpt 6 58673.411 ± 23803.125 ops/s PerformanceTest.MatchingCapacity thrpt 6 64863.127 ± 33194.262 ops/s PerformanceTest.MismatchingCapacity thrpt 6 58921.951 ± 21346.733 ops/s PerformanceTest.OversizedCapacity thrpt 6 62658.432 ± 32061.866 ops/s
内容的提问来源于stack exchange,提问作者N4ppeL
相关产品推荐
相关产品推荐

