众所周知StringBuffer是安全的,而StringBuilder是不安全的,他们都有append方法,但具体实现细节你了解过吗?为什么有时候用着用着就​​OutOfMemoryError​​,在哪报的

以StringBuffer.append(str)为例

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_java
上图可见,线程安全是因为​​​synchronized​​,正真的实现调用的是父类方法

super.append(str)

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_java_02
父类核心方法​​​ensureCapacityInternal​​确保容量足够,是怎么确保的呢?

ensureCapacityInternal(int)

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_底层实现_03
​​​Arrays.copyOf​​​只是复制用的,一会儿再看,先看一下​​newCapacity(minimumCapacity))​

newCapacity(minimumCapacity))

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_java_04
下面这句就是确保容量足够的核心代码

int newCapacity = (value.length << 1) + 2;

可以看出来,为了确保容量足够,java会将容量扩大到原来的两倍再加上2,但为了确保容量合理不会超过最大值,在返回前进行了判断。当容量大到一定程度会触发​​hugeCapacity​​​方法

原来​​​OutOfMemoryError​​​内存溢出在这个位置,原因就是申请的内存太大了,大到超过​​Integer.MAX_VALUE​​​,看一下​​hugeCapacity​​​,系统有确保不要超过一个最大阈值​​MAX_ARRAY_SIZE​​​,具体为:
StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_后端_05

回到​​ensureCapacityInternal(int)​​​继续深挖​​Arrays.copyOf(char[] original, int newLength)​

Arrays.copyOf(char[] original, int newLength)

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_后端_06
最终挖到底了,系统底层实现​​​System.arraycopy​

System.arraycopy

StringBuffer.append(str)之OutOfMemoryError打破砂锅问到底_内存泄漏_07