2015-10-21 129 views
7

我想用盡可能小的空間將System.currentTimeInMillis存儲在內存中。因爲我必須將數百萬個數據存儲在內存中。我的Bitset的大小是多少?

我把它轉化爲binaryString這給了我41 bits

這裏是我的程序

public class BitSetSize { 
    public static void main(final String[] args) { 
     final long currentTimeMillis = System.currentTimeMillis(); 
     final String currentTimeToBinaryString = Long.toBinaryString(currentTimeMillis); 
     System.out.println("Size in bits: " + currentTimeToBinaryString.length()); 

     final BitSet bitSet = BitSet.valueOf(new long[]{currentTimeMillis}); 
     System.out.println("Bitset length: " + bitSet.length()); 
     System.out.println("Bitset size: " + bitSet.size()); 

     System.out.println("Size of biset object(bytes): " + MemoryMeasurer.measureBytes(bitSet)); 
    } 
} 

但是當我運行它,我得到

Size in bits: 41 
Bitset length: 41 
Bitset size: 64 
Size of biset object(bytes): 48 

問題
- 爲什麼bitSet.length()bitSet.size()有何不同?我認爲length()是正確的?
- 我正在使用memory-measurer瞭解bitSet的大小,但它告訴我48 bytes,爲什麼不是(41/8) byte

我的BitSet困惑

+0

64位(可能是'long')是實際用來保存數據的BitSet的位數。 (它不能分配41位) – aioobe

+0

已知時間在彼此的一定範圍內嗎?你可以扔掉每個「長」的高字節而不會丟失信息嗎? –

回答

4

首先,我想建議正確的工具來分析JVM中的對象佈局方案 - JOL。在你的情況(java -jar jol-cli/target/jol-cli.jar internals java.util.BitSet)約爾將產生以下結果:

Running 64-bit HotSpot VM. 
Using compressed references with 3-bit shift. 
Objects are 8 bytes aligned. 
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 

java.util.BitSet object internals: 
OFFSET SIZE TYPE DESCRIPTION     VALUE 
     0  4   (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
     4  4   (object header)    00 00 00 00 (00000000 00000000 00000000 00000000) (0) 
     8  4   (object header)    f4 df 9f e0 (11110100 11011111 10011111 11100000) (-526393356) 
    12  4  int BitSet.wordsInUse    0 
    16  1 boolean BitSet.sizeIsSticky   false 
    17  3   (alignment/padding gap)  N/A 
    20  4 long[] BitSet.words     [0] 
Instance size: 24 bytes (reported by Instrumentation API) 
Space losses: 3 bytes internal + 0 bytes external = 3 bytes total 

你的計算是因爲靜態字段不正確,從而空BitSet本身保留24個字節。請注意,這些計算不是100%確切的,因爲它沒有考慮到long[]對象的大小。因此,正確的結果是java -jar jol-cli/target/jol-cli.jar externals java.util.BitSet

Running 64-bit HotSpot VM. 
Using compressed references with 3-bit shift. 
Objects are 8 bytes aligned. 
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] 

[email protected] object externals: 
      ADDRESS  SIZE TYPE    PATH       VALUE 
     7ae321a48   24 java.util.BitSet        (object) 
     7ae321a60   24 [J    .words       [0] 

這意味着一個空BitSet本身使用的48個字節包括長陣列。你也可以在不同的虛擬機模式下得到估計的對象佈局java -jar jol-cli/target/jol-cli.jar estimates java.util.BitSet

1

請參閱Java文檔。

每個位組具有電流的大小,這是目前在由比特組使用空間 的比特數。請注意,該大小與位設置的實現相關,所以它可能隨實現而改變。位集的長度與位集的邏輯長度有關,並且是與實現無關地定義的 。

2

您目前的代碼不能存儲數百萬的longSystem.currentTimeInMillis)。你可以使用trove TLongHashSet,或者你應該看看sparse bitset。但是BitSet有int索引,所以你應該從currentTimeInMillis長時間壓縮到int。例如。 bitSetIndex =(int)(currentTimeInMillis - initialTime)。它會給你從initialTime開始的2^32毫秒(〜50天)間隔。

//store sample for bitset: 
bitSet.set(System.currentTimeInMillis()); 

EDIT

一個位集合對象分配在堆上多於100個字節。所以你應該重用一個BitSet對象來獲得很多很長的值。最簡單的方法是在BitSet中使用long值作爲索引,並在此索引處將value設置爲true。但是有幾個問題(我把他們描繪以上):

  1. BitSet中有不長
  2. java.util.BitSet中不存儲effecient INT指數。
+0

'不能存儲數百萬長',你能解釋爲什麼嗎? – daydreamer

+0

我編輯我的答案 – sibnick

0

正如BetaRide所提到的,BitSet所採用的實際大小是特定於實現的。也就是說,在Oracle/OpenJDK實現中(至少在6,7和8中),狀態的基本元素是long[] of words。這意味着大小總是64的倍數。

對於48個字節,我數中的代碼:

  • 16字節for the BitSet object itselflong[]對象
  • 20個字節(16爲對象,4的長度)
  • 8字節對於陣列的內容(每個元素是8個字節,但只有一個)
  • 4個字節用於int wordsInUse
  • 1個字節用於boolean sizeIsSticky

其中產量49--距離你所看到的48不遠。如果那些object headers are compressed,但填充也引入,那麼這可能是48來自何處。

1

爲什麼bitSet.length()和bitSet.size()有區別?我認爲長度()是正確的?

BitSet.size()是它用來存儲位值的內部數據結構的大小。由於BitSet內部使用long[]陣列,因此大小總是64位的倍數。例如。如果將第64位設置爲BitSetBitSet必須增加long[]數組的容量才能存儲該值,因爲每個long只能「存儲」64位。例如。

BitSet bitSet = new BitSet(); 
for (int i = 0; i <= 64; i++) { 
    bitSet.set(i, true); 
    System.out.println(bitSet.size()); 
} 

BitSet.length()返回在BitSet實際佔用的比特。所以,如果你創建一個新的BitSet它的長度是0.如果你設置第4位的長度將是5. size將保持64,因爲只需要一個長的來存儲5位。

BitSet bitSet = new BitSet(); 
System.out.println(bitSet.length()); // 0 
bitSet.set(4, true); 
System.out.println(bitSet.size()); // 64 
System.out.println(bitSet.length()); // 5 

我使用內存測量,以瞭解位集合的大小,但它告訴我48個字節,爲什麼不(第41/8)字節?

由於內存填充。也被稱爲data structure alignmentBitSet對象在內存中需要數學41個字節。

  • 8字節爲目標首標的
  • 爲所述陣列中的 long[]
  • 8個字節用於long
  • 20字節
  • 4個字節用於爲sizeIsStickybooleanwordsInUseint可變
  • 1字節

但jvm無法分配41位,因此會將其舍入到8的下一個倍數。即48。

此大小可能會有所不同,因爲對象頭大小可能因JVM實現而異。所以如果對象頭是16字節。總數將爲49,jvm將其舍入到8的下一個倍數。在這種情況下,56.

相關問題