ArrayList动态增长方式

ArrayList动态增长方式

ensureCapacityInternal-> ensureExplicitCapacity->grow-> hugeCapacity

  1. ensureCapacityInternal:判断数组是否非空,若为空,比较DEFAULT_CAPACITY(ArrayList默认容量为10)与minCapacity设最大值为容量值
  2. ensureExplicitCapacity:modCount++,若minCapacity大与数组长度时调用grow扩容
  3. grow扩容原数组长度50%,与minCapacity比较取最大值,若最终取值大与MAX_ARRAY_SIZE,调用hugeCapacity最大容量函数扩容
    注:上两步的比较均采用相减与0比较的方式,针对最大值溢出Integer.MAX_VALUE为负的情况
  4. hugeCapacity判断容量值是否<0(若int值大与Integer.MAX_VALUE,则内存溢出),是则抛出OOM异常。设最终容量为(minCapacity >MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
    注:试图分配更大数组时可能导致OutOfMemoryError:被请求数组的size超出VM界限
  5. grow调用Arrays.copyOf()复制数组

总结:

 分配次数
1千需要分配 11次
1万一级需要分配17次
10万 需要分配23次
100万需要分配28次

 因扩容为自增0.5倍,为避免不必要的内存泄漏,应该考虑用ensureCapacity方法

 申请扩容(大与DEFAULT_CAPACITY)的四种结果:
1. 原容量的1.5倍
2. 用户自定义minCapacity值
3. MAX_ARRAY_SIZE(等于Integer.MAX_VALUE-8)
4. Integer.MAX_VALUE


补充相关小知识点:

1.前面grow方法中为什么要采用相减与0比较的方式

public static void main(String[] args) {
    // Integer的取值范围-2147483648 ~ 2147483647 (-2^31 ~ 2^31-1)
    int i = Integer.MAX_VALUE + 1;
    int max = Integer.MAX_VALUE;
    int min = Integer.MIN_VALUE;
    System.out.println(i > max-8);// false
    System.out.println(i - max > 0);// true
    System.out.println(min == i);// true
    System.out.println(min == i);// true
    arraytest();
}

2.Arrays.copyof(···)与System.arraycopy(···)方法比较

//Arrays.copyof方法
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)//判断是否为Object类型
        ? (T[]) new Object[newLength]//若为Object类型生成一个Object数组
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        //否则生成一个newType数组类型的数组
        //Class.getComponentType():返回表示数组组件类型的 Class。如果此类不表示数组类,则此方法返回 null。
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

//System.arraycopy方法
public static native void arraycopy(Object src,  int  srcPos,
                                       Object dest, int destPos,
                                       int length);

总结:
System.arraycopy可以指定复制目标数组与起始复制位置。嗯~思考一下作用:可以实现向数组中部插入删除耶~

而Arrays.copyof只是返回一个新数组,只能复制原数组从0到newLength的值,内部调用System.arraycopy实现

3.关于MAX_ARRAY_SIZE

/**
 * The maximum size of array to allocate.
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个为什么要取一个Integer.MAX_VALUE - 8呢?

  • 原注释提到说这块区域是为了存放一些头数据
  • 其实也是为了避免一些机器内存溢出,-8 是为了减少出错的几率
  • 数组的长度太大了,会导致JVM内存溢出,所以当你的内存足够大时,数组的扩容接近内存的最大值时,数组不会直接扩满,还会留一些空间(8这一个字节),保证这时候JVM还能有些内存空间去做GC,清除其他不用的内存来缓冲

关于这个问题的答案,保留个人想法,欢迎大家指正错误

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值