2015-10-21 4 views
7

मैं न्यूनतम स्थान संभव के साथ स्मृति में System.currentTimeInMillis स्टोर करना चाहता हूं। क्योंकि मुझे लाखों लोगों को स्मृति में स्टोर करना है।मेरे बिसेटसेट का आकार क्या है?

मैं इसे 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() सही है?
- bitSet के आकार के बारे में जानने के लिए मैं memory-measurer का उपयोग कर रहा हूं, लेकिन यह मुझे 48 bytes बताता है, यह (41/8) byte क्यों नहीं है?

मैं उलझन में

+0

64 बिट्स (संभवतः एक 'लम्बा') में अनुमानित ऑब्जेक्ट लेआउट प्राप्त कर सकते हैं बिट्ससेट की बिट्स की संख्या है जो वास्तव में आपके डेटा को पकड़ने के लिए उपयोग में होती है। (यह 41 बिट आवंटित नहीं कर सकता है।) – aioobe

+0

क्या समय एक दूसरे की एक निश्चित सीमा के भीतर जाना जाता है? क्या आप सूचना खोने के बिना प्रत्येक 'लम्बे' के ऊंचे बाइट फेंक सकते हैं? –

उत्तर

4

सबसे पहले मैं JVMs - JOL में ऑब्जेक्ट लेआउट स्कीम का विश्लेषण करने के लिए सही टूल की सलाह देना चाहता हूं। आपके मामले में (java -jar jol-cli/target/jol-cli.jar internals java.util.BitSet) JOL निम्नलिखित परिणाम पैदा करता है:

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

देखें जावा BitSet के डॉक हूँ।

प्रत्येक बिट सेट का वर्तमान आकार होता है, जो वर्तमान में बिट सेट द्वारा उपयोग में की बिट्स की संख्या है। ध्यान दें कि आकार बिट सेट के कार्यान्वयन से संबंधित है, इसलिए यह कार्यान्वयन के साथ बदल सकता है। बिट सेट की लंबाई बिट सेट की तार्किक लंबाई से संबंधित है और कार्यान्वयन के स्वतंत्र रूप से परिभाषित है।

2

आपके मौजूदा कोड long (System.currentTimeInMillis) के लाखों लोगों के लिए भंडारण नहीं हो सकता। आप ट्रोव TLongHashSet का उपयोग कर सकते हैं या आपको sparse bitset पर देखना चाहिए। लेकिन बिटसेट में इंट इंडेक्स है, इसलिए आपको वर्तमान टाइमइमिलिस से int तक लंबे समय तक संपीड़ित करना चाहिए। जैसे bitSetIndex = (int) (currentTimeInMillis - प्रारंभिक समय)। यह आपको प्रारंभिक समय से शुरू 2^32 मिलीसेक (~ 50 दिन) अंतराल देता है।

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

संपादित

एक BitSet वस्तु ढेर पर 100 से अधिक बाइट्स आवंटित करता है। तो आपको बहुत से मूल्यों के लिए एक बिटसेट ऑब्जेक्ट का पुन: उपयोग करना चाहिए। सबसे आसान तरीका बिटसेट के अंदर इंडेक्स के रूप में लंबे मूल्य का उपयोग करना है और इस इंडेक्स पर मान को सही मानना ​​है। लेकिन वहाँ कई समस्याएं (मैं उन्हें ऊपर वर्णित है) कर रहे हैं:

  1. BitSet पूर्णांक सूचकांक लंबे समय तक नहीं
  2. java.util.BitSet स्मृति कुशल नहीं है।
+0

'लाखों लंबे समय तक भंडारण नहीं हो सकता है, क्या आप कृपया बता सकते हैं क्यों? – daydreamer

+0

मैं अपना जवाब संपादित करता हूं – sibnick

0

जैसा कि बीटाराइड का उल्लेख किया गया है, बिटसेट ले जाने वाला वास्तविक आकार कार्यान्वयन-विशिष्ट है। उस ने कहा, ओरेकल/ओपनजेडीके कार्यान्वयन में (कम से कम, 6, 7, और 8 में), राज्य का मूल तत्व long[] of words है। इसका मतलब है कि आकार हमेशा 64 का एक बहु है।

48 बाइट्स का सवाल है, मैं कोड में गिनती: (लंबाई के लिए वस्तु के लिए 16, 4)

  • 16 बाइट्स long[] वस्तु के लिए for the BitSet object itself
  • 20 बाइट
  • 8 बाइट्स सरणी की सामग्री के लिए (प्रत्येक तत्व 8 बाइट्स की है, लेकिन आप केवल एक है) boolean sizeIsSticky
  • 01 के लिए int wordsInUse
  • 1 बाइट के लिए
  • 4 बाइट

जो 49 उत्पन्न करता है - जो आप देख रहे हैं उससे दूर नहीं है। यदि वे object headers are compressed हैं, लेकिन पैडिंग भी पेश किया गया है, तो शायद यह है कि 48 कहां से आ रहा है।

1

bitSet.length() और bitSet.size() भिन्न क्यों है? मुझे लगता है कि लंबाई() सही है?

BitSet.size() बिट डेटा को स्टोर करने के लिए उपयोग की जाने वाली आंतरिक डेटा संरचना का आकार है। चूंकि BitSet आंतरिक रूप से long[] सरणी का उपयोग करता है, आकार हमेशा 64 बिट्स का एक से अधिक होता है। जैसे यदि आप BitSet में 64 वें बिट को सेट करते हैं तो BitSet को उस मान को स्टोर करने के लिए 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 

मैं bitSet के आकार के बारे में जानने के लिए स्मृति-मापक का उपयोग कर रहा है, लेकिन यह मुझे 48 बाइट्स बताओ, क्यों यह (41/8) बाइट नहीं है?

मेमोरी पैडिंग के कारण। data structure alignment के रूप में भी जाना जाता है। BitSet ऑब्जेक्ट को स्मृति में गणितीय 41 बाइट की आवश्यकता है। वस्तु हेडर के लिए

  • 8 बाइट्स सरणी में long के लिए long[]
  • 8 बाइट्स के लिए
  • 20 बाइट sizeIsStickyboolean के लिए wordsInUseint चर
  • 1 बाइट के लिए
  • 4 बाइट

लेकिन जेवीएम 41 बिट्स आवंटित नहीं कर सकता है, इसलिए यह इसे 8 के अगले एकाधिक भाग में गोल करता है। यह 48 है।

यह आकार भिन्न हो सकता है, क्योंकि ऑब्जेक्ट हेडर आकार एक JVM कार्यान्वयन से दूसरे में भिन्न हो सकता है। तो यदि ऑब्जेक्ट हेडर 16 बाइट्स है। कुल 49 होगा और जेवीएम इसे 8 के अगले एकाधिक भाग में ले जाएगा।इस मामले में 56.

संबंधित मुद्दे