ArrayList 擴容 Android Java 真的不一樣

以前學java基礎的時候 看過ArrayList的擴容機制

實現原理是下面這樣 當時做的筆記
ArrayList擴容機制 在jdk1.7前是 *3/2+1 在jdk1.7開始就是 old+(old>>1) ->1.5倍擴容

然后今天看內存優化的時候 突然看到這個 就看了看android的ArrayList的源碼
一看嚇一跳 原來和JDK里面的算法有點不一樣

然后馬上進入JDK里面的源碼 看了ArrayList 版本 1.8.0

  • JDK 1.8 ArrayList源碼

默認容量是10 初始化是10
private static final int DEFAULT_CAPACITY = 10;

直接傳入 size初始化不會擴容 就直接創建一個新的數組


Paste_Image.png

直接看Add方法 在add的時候 如果容量不夠 肯定會擴容

Paste_Image.png
Paste_Image.png

發現這個函數

Paste_Image.png

最后發現 實現代碼在這里
來分析一下 實現方式

Paste_Image.png
Paste_Image.png

所以可以總結 JDK里面實現方式是 先1.5倍擴容 如果擴容之后還是小于現在需要的 就設置size為需要的
然后得到新的size 拿到新的size去和最大的MAX_Array_SIZE去比較 按照他的規則實現
最后創建一個新的數組 把原來的加載新的前面 后面就是空的

  • 再看看Android內部的實現

初始大小是12 還說什么 12要好點 湊個團圓嗎?

Paste_Image.png

/**
* The minimum amount by which the capacity of an ArrayList will increase.
* This tuning parameter controls a time-space tradeoff. This value (12)
* gives empirically good results and is arguably consistent with the
* RI's specified default initial capacity of 10: instead of 10, we start
* with 0 (sans allocation) and jump to 12.
*/
private static final int MIN_CAPACITY_INCREMENT = 12;

同樣的先看 add方法

Paste_Image.png

再看看addAll方法 觀察 Android在這里做了處理 在addAll的時候 有新的擴容機制

Paste_Image.png

發現還是和上面add的時候一樣 但是進去的size不同了

Paste_Image.png

Paste_Image.png

最大的不同來了 Android是在old+newPartSize=newSize 之后 對newSize擴容 而JDK 不是 JDK是newSize=old+old>>2 在比較newSize與需要的Size的大小

所以這里得出總結

  • JDK 中 ArrayList的擴容機制 需要的size
    1 新的Size1.5倍擴容 newSize=old+old>>1
    2 發現擴容之后 還是不夠 就設置為 需要的Size 在經過一次判斷 大于設置的最大就給設置為Int最大值 否則就是int最大值-8(也就是默認設置的最大值)
  • Android實現原理
    1 newSize=oldSize+newPartSize 然后對這個新的newSize進行 <12就設置為12 否則就 1.5倍擴容

舉個例子
oldSzie=20 addAll(newPart) newPartSize=50;

JDK 中 old+old>>1=35 35<70 newSize=70 ---> Size=70

Android中
20+50 ---->70 70-1=69>6--->69+34=103 size=103

看下測試數據
Android版本的

Paste_Image.png

JDK的 與 想法一致

Paste_Image.png

oldSzie=20 addAll(newPart) newPartSize=10;

 for (int i = 0; i < 20; i++) {
        data.add("Daemon" + i);

           Class d = data.getClass();

    /*
    * 得到類中的所有屬性集合
    */
    try {
        Field fs = d.getDeclaredField("elementData");
        fs.setAccessible(true);
        System.out.println("elementData.size " +i+"---"+ ((Object[])fs.get(data)).length);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    }

前20個加載完 初始化10 第11個進來的時候1.5被擴容 15 第16個進來擴容22 20個加載完畢 然后 加載10個 擴容 33 最后為33

當addAll(10) 的時候 oldSize+oldSize/2=33 所以在33之前 都能加載進去 不會擴大

JDK 實現


Paste_Image.png

Android 版本的 初始化 12 第13個進來擴容1.5倍 18 第19個進來擴容1.5 27
以后addAll因為算大不一樣是 size+newpartsize 即 20+10-1擴容 也就是 43正確

Paste_Image.png

下班了 在路上手機碼完

圖片發自簡書App
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,242評論 25 708
  • 1.集合 紅色的表示接口,黑色的表示實現類。 ArrayList 、 LinkedList 、 Vector 的底...
    zthh閱讀 1,160評論 0 2
  • 一、基本數據類型 注釋 單行注釋:// 區域注釋:/* */ 文檔注釋:/** */ 數值 對于byte類型而言...
    龍貓小爺閱讀 4,288評論 0 16
  • 文/慕雪 從此,希望文字中的我能夠替生活中的我好好墮落,生活里的我也替文字中的我好好生活...
    小慕雪閱讀 1,027評論 4 10
  • 一、 CAShapeLayer的簡介 關于CAShapeLayer比較好的文章:放肆地使用UIBezierPath...
    LiYaoPeng閱讀 1,534評論 0 2