日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

ArrayList源碼中的MAX_ARRAY_SIZE

作者:hygge999 更新時間: 2022-10-11 編程語言
/**
 * 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;

看過 Arraylist 代碼的小伙伴是不是看到這個總會有疑惑:

  • 為什么 MAX_ARRAY_SIZE 是等于 Integer.MAX_VALUE - 8,為啥不是-16或者其他數字。

我看了很多回答,他們總是把這個 十進制的8 和 java的對象頭聯系在一起說,我到現在都不能理解這兩個怎么畫等號的。

思索了很久,再結合源碼的注釋,我開始想是不是兄弟們把這個問題想復雜了啊。

注釋清清楚楚寫著:Some VMs(一些VM)在數組中會有保留字,嘗試分配更大的數組可能會導致OutOfMemoryError。

所以這個 Integer.MAX_VALUE - 8 其實是為了保證這些(Some VMs)減少報錯的幾率(?)

這里我們打個問號,下面我們分析分析。

這個變量只在 grow() 和 hugeCapacity() 兩個方法里面用到了。

先看看 grow() 方法:

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

里面第二個if里面會判斷 newCapacity 是否大于了 MAX_ARRAY_SIZE,大于了就調用 hugeCapacity() 方法。

再看看 hugeCapacity() 方法:

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

為什么第一個if判斷 minCapacity 小于 0 就是代表溢出,minCapacity 什么時候會溢出了,就是當我們的數組已經達到 Integer 的最大值 2^31-1 的時候,他增加一個元素后, 即 minCapacity 等于 2^31 時,這個數從二進制變成十進制就是個負數,所以直接判斷 minCapacity 是否小于 0 就能判斷是否溢出了。

我再強調一下幾個變量的意義:

  • newCapacity :預計擴容后的數組長度。
  • minCapacity : 原數組增加元素后需要的數組長度。
  • MAX_ARRAY_SIZE : Integer.MAX_VALUE - 8

看到return里面的三元表達式,再結合 grow() 方法里面的第二個if判斷,思路是不是清晰起來了。

  • 首先 預計擴容后的數組長度(newCapacity) 大于了 MAX_ARRAY_SIZE
  • 再判斷 原數組增加元素后需要的數組長度(minCapacity ) 是不是大于 MAX_ARRAY_SIZE
  • 如果大于了 MAX_ARRAY_SIZE,那還是會將 預計擴容后的數組長度(newCapacity) 置為 Integer.MAX_VALUE
  • 如果不大于 MAX_ARRAY_SIZE ,則將 預計擴容后的數組長度(newCapacity) 置為 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)

你會發現他依舊可能會擴容到 Integer.MAX_VALUE,所以我們可以得知:

Arraylist 的最大容量依舊是 Integer.MAX_VALUE ,而不是 Integer.MAX_VALUE - 8。

很多人看到 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 這句代碼,就說 Arraylist 的最大容量是 Integer.MAX_VALUE - 8 ,這是不對的。


到這里可能還會有人會接著問,那最后都是會到 Integer.MAX_VALUE ,那用一個 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8) 做判斷有啥意義。

所以我這里就有了文章開始的那些猜測,這個 MAX_ARRAY_SIZE 值只是為了保證這些(Some VMs)減少報錯的幾率的。

如果沒有這個 MAX_ARRAY_SIZE 的話,這些(Some VMs)在 數組長度為 Integer.MAX_VALUE 的 2/3 左右的時候,一旦觸發擴容,newCapacity 直接大于 Integer.MAX_VALUE - 8,然后報錯 。

如果有了 MAX_ARRAY_SIZE 的話,那么這些(Some VMs)會在 數組長度為 Integer.MAX_VALUE - 8 的時候,再增加元素才會報錯,其他VM會正常的擴容到 nteger.MAX_VALUE。

這樣極大的減少了這些(Some VMs)的報錯幾率。并且為這些(Some VMs)增加了接近1/3的實際儲存容量。


最后說明,以上絕大部分都是我的推理,我至此也沒查到為啥一定是 8 這個數字,我只能想到這個十進制的8代表二進制數組的最后四位為0,除此之外我并不曉得在這里的具體含義。

望大家一起探討探討。

原文鏈接:https://blog.csdn.net/z55947810/article/details/127249701

欄目分類
最近更新