今天我不小心看到了jdk9和8中间arraylist的一些小改动。
扩容的方法和逻辑其实大相径庭。
但是一个小细节引起了我的注意。
就是jdk9将jdk8的add方法进行了拆分。
以下是jdk9中的ArrayList相关的add方法。
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
以下是1.8
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
可以看到
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
这么一段话。
翻译一下
这个helper方法从add(E)中分离出来,以将方法字节码大小保持在35以下(默认值为-XX:MaxInlineSize),这有助于在C1编译循环中调用add(E)。
然后我就详细了解了一下 这个jvm参数 。
Integer specifying maximum number of bytecode instructions in a method
which gets inlined. 翻译过来是 设置可以被优化的内敛方法的最大的字节码的指令数。
这个时候问题来了,什么是内联优化呢?
方法内联就是把调用方函数代码"复制"到调用方函数中,减少因函数调用开销的技术 函数调用过程
1、首先会有个执行栈,存储它们的局部变量、方法名、动态连接
2、当一个方法被调用,一个新的栈帧会被加到栈顶,分配的本地变量和参数会存储在这个栈帧
3、跳转到目标方法代码执行
4、方法返回的时候,本地方法和参数被销毁,栈顶被移除
5、返回原来的地址执行https://www.oracle.com/java/technologies/javase/exactoptions-jsp.html
我对于这个玩意儿的大概理解就是说,如果一个方法中调用了另外一个方法,jvm内部会通过方法内联这一优化手段,将两个方法的字节码整合成一个方法。
然后就是上述的 -XX:MaxInlineSize这一参数了。这一参数的默认值是35.
意思就是说,当方法的字节码小于35时,就能触发方法内联。
本身Arraylist的add方法是一个调用频率非常高的方法,在1.8中,这个方法的字节码较长,触发不了方法内联这一优化手段。
所以jdk9中将add方法拆分成了两个方法。
所以我的结论是,尽量将方法拆分的比较细,可以在一定程度上对程序的运行速度有所提升。