Java Resizable Array

原文連接:http://tutorials.jenkov.com/java-performance/resizable-array.html,若有侵權,立刪html

Java Resizable Array

  • Java Resizable Array - GitHub Repository
  • Resizable Array Use Case
  • Resizable Array DesignExpand on Write
    • Keeping Track of Free Blocks
  • Freeing Arrays
  • Using the ResizableArrayBuffer
    • Creating a ResizableArrayBuffer
    • Obtaining a ResizableArray Instance
    • Writing to a ResizableArray
    • Reading From a ResizableArray
    • Freeing a ResizableArray

  有時候咱們爲了快速便捷的讀取數據,想把數據保存在單個連續的數組裏。這就須要數組是能夠調節大小的,或者是能夠擴張的。可是在Java中數組的大小是不能夠調節的。你必須親自實現一個可調節大小的數組,在本文中我將展現如何實現這個數組java

Java Resizable Array-GitHub Repository

  源代碼哦:https://github.com/jjenkov/java-resizable-arraygit

  包含了三個classes和兩個測試類github

Resizable Array Use Case

  想象下若是你有一個接受不一樣數據的Server,最小的數據4KB,大的1MB或者更大。數組

  若是Server同一時間有1000K+的訪問鏈接,咱們須要知道要爲數據提早分配多大的空間。咱們不能僅僅只是分配一個最大的空間(1MB&16MB)爲每一個buffer。當有一千條鏈接訪問Server時(100.000 × 1MB = 100GB),須要100GB的空間。測試

  換一種思路,咱們先從最小的信息開始處理,若是信息size超過了最小信息,那麼咱們從新分配一塊空間並把原來的信息複製過去。若是信息又超過了現有的容量,那麼再次分配並複製spa

  使用這種策略,大多數信息將會使用最小buffer。這也就意味着Server的內存使用會變得很是高效,(100.000×4KB = 400MB),即便鏈接訪問達到(1000.000 × 4KB = 4GB)。大多數Server也能hold住code

Resizable Array Design

  resizable array 包含兩個部分orm

    • ResizableArray
    • ResizableArrayBuffer

  ResizableArrayBuffer包含一個單一,高容的數組。這個數組被分爲三個部分。一個部分爲small arrays,一個爲medium size arrays 和 large array。htm

  ResizableArray就表示單一,高容的數組,它的數據存儲在ResizableArrayBuffer中的數組。

  有圖有真相

                

  爲了在ResizableArrayBuffer中的large array爲各個大小不一的message預留空間,咱們須要保證array不會被任意大小的message填充滿。例如,接受了大量的small mesages,並不會佔用所有的內存,可是卻會阻塞Server接受medium和large message。類似的,接受大量的large或medium message也不會佔用全部的內存,但卻會使得另外連個message type產生阻塞。

  假如全部的message都是從small messages開始,若是大量的small arrays被耗盡,不管medium array或large array是否有空間,都不會分配新的array。可是若是將small arrays的大小設置的合理,這種狀況發生的機率就會下降。

  即使small message部分所有被佔用了,small message仍是有可能會grow爲medium and large messages的。

Keeping Track of Fress Blocks

  large array 在ResizableArrayBuffer中被分爲三個部分,每一個部分又被分爲不少小塊。每一個小塊在每一個部分中有着相同的大小。

  當全部的塊在其所處的部分有着相同的大小時,它是很容易去跟蹤那些使用着的塊和沒有使用的塊。你可使用一個queue(隊列)來保存每一個塊的開始索引。對於每一個部分都須要有這麼一個queue(隊列),一個queue(隊列)去跟蹤可用的small blocks,medium blocks 和 large blocks 一樣是這樣的。

  Allocating a block from any of the sections can be accomplished simply by taking the next free block start index from the queue associated with the desired section. Freeing a block is done by putting the start index back into the corresponding queue.(能力有限)

  對於queue(隊列)我曾經用一個簡單的Ring Buffer 實現過,連接:http://tutorials.jenkov.com/java-performance/ring-buffer.html

Expand on Write

  當你向array中寫入數據時,Resizable array將會本身expand。若是你嘗試向其中寫入更多的數據,可是 array 沒有多餘的空間,它會被分配一個新的更大的 block 而且把原有的數據所有複製過去,以前的使用的block就free掉。

Freeing Arrays

  一旦你得到了一個更大的array,你就應該釋放掉原來的array,以便它能夠存儲別的message。

  Using the ResizableArrayBuffer

  我教你如何使用ResizableArrayBuffer

  Creating a ResizableArrayBuffer

  首先你必須建立一個ResizableArrayBuffer

 1 int smallBlockSize  =    4 * 1024;
 2 int mediumBlockSize =  128 * 1024;
 3 int largeBlockSize  = 1024 * 1024;
 4 
 5 int smallBlockCount  = 1024;
 6 int mediumBlockCount =   32;
 7 int largeBlockCount  =    4;
 8 
 9 ResizableArrayBuffer arrayBuffer =
10         new ResizableArrayBuffer(
11                 smallBlockSize , smallBlockCount,
12                 mediumBlockSize, mediumBlockCount,
13                 largeBlockSize,  largeBlockCount);

  This example creates a ResizableArrayBuffer with a small array size of 4KB, medium array size of 128KB and a larger array size of 1MB. The ResizableArrayBuffer contains space for 1024 small arrays (4MB in total), 32 medium arrays (4MB in total) and 4 large arrays (4MB in total) - for a full shared array size of 12MB.(不想翻了)

Obtaining a ResizableArray Instance

  得到一個ResizableArray instance,調用ResizableArrayBuffer`s getArray()方法。

 ResizableArray resizableArray = arrayBuffer.getArray(); 

  這個例子會得到一個很小的ResizableArray(4KB)

  Writing to a ResizableArray

  你能夠調用ResizableArray本身的write()方法。你能夠重構它

1 ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
2 
3 for(int i=0; i < 1024; i++){
4     byteBuffer.put((byte) i);
5 }
6 byteBuffer.flip():
7 
8 int bytesCopied = resizableArray.write(byteBuffer);

  這個例子將ByteBuffer中的數據copy到ResizableArray中的array(block),返回值是複製了多少個字節數。

  一種狀況是ByteBuffer中的數據大於ResizableArray的容量,那麼ResizableArray將嘗試expand自身的空間爲了ByteBuffer中的數據。若是ResizableArray在expanding後不能包含全部的ByteBuffer數據,write()方法將會返回-1而且也不會複製data。

Reading From a ResizalbeArray

  當你從ResizableArray讀取數據時,你能夠直接在全部ResizableArray實例共享的共享數組中讀取。ResizableArray包含如下幾個字段:

1 public byte[] sharedArray = null;
2 public int    offset      = 0;
3 public int    capacity    = 0;
4 public int    length      = 0;

  shareArray字段引用全部的ResizableArray實例中的共享array,這是保存在ResizableArrayBuffer中的內部array。

  offset字段包含着共享array中的開始索引。

  capacity字段包含ResizableArray實例中分配的共享數組中block的size。

  length字段包含多少正在使用的block

  去讀取卸載ResizableArray中的數據時,是從shareArray[offset]到shareArray[offset+length-1]。

Freeing a ResizableArray

  一旦你使用完了ResizableArray,你就要free它。僅須要調用ResizableArray中的free()方法便可。

resizableArray.free();

  調用free()方法負責返回使用過的block到正確的queue,無論分配給ResizableArray中block的大小。

相關文章
相關標籤/搜索