2015-10-21 3 views
2

Это привлекло мое внимание и внимание со вчерашнего дня. Я пытаюсь хранить биты в Java и попадать в память.Есть ли все-таки, чтобы хранить бит в Java без накладных расходов памяти?

Мой первый вопрос, касающийся же What is size of my Bitset?

На основе ответов я посмотрел на другие ссылки и нашли Memory Usage руководство.

Затем я посмотрел на BitSet исходный код, который выглядит как

public class BitSet implements Cloneable, java.io.Serializable { 
    /* 
    * BitSets are packed into arrays of "words." Currently a word is 
    * a long, which consists of 64 bits, requiring 6 address bits. 
    * The choice of word size is determined purely by performance concerns. 
    */ 
    private final static int ADDRESS_BITS_PER_WORD = 6; 
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; 
    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1; 

    /* Used to shift left or right for a partial word mask */ 
    private static final long WORD_MASK = 0xffffffffffffffffL; 

    /** 
    * @serialField bits long[] 
    * 
    * The bits in this BitSet. The ith bit is stored in bits[i/64] at 
    * bit position i % 64 (where bit position 0 refers to the least 
    * significant bit and 63 refers to the most significant bit). 
    */ 
    private static final ObjectStreamField[] serialPersistentFields = { 
     new ObjectStreamField("bits", long[].class), 
    }; 

    /** 
    * The internal field corresponding to the serialField "bits". 
    */ 
    private long[] words; 

    /** 
    * The number of words in the logical size of this BitSet. 
    */ 
    private transient int wordsInUse = 0; 

    /** 
    * Whether the size of "words" is user-specified. If so, we assume 
    * the user knows what he's doing and try harder to preserve it. 
    */ 
    private transient boolean sizeIsSticky = false; 

    /* use serialVersionUID from JDK 1.0.2 for interoperability */ 
    private static final long serialVersionUID = 7997698588986878753L; 

    /** 
    * Given a bit index, return word index containing it. 
    */ 
    private static int wordIndex(int bitIndex) { 
     return bitIndex >> ADDRESS_BITS_PER_WORD; 
    } 

..... 
} 

В соответствии с расчетом, основанным на Memory Guide, это то, что я вычислил

8 Bytes: housekeeping space 
12 Bytes: 3 ints 
8 Bytes: long 
12 Bytes: long[] 
4 Bytes: transient int // does it count? 
1 Byte : transient boolean 
3 Bytes: padding 

Это подводит к 45 + 3 bytes (padding to reach multiple of 8)

Это означает пустой BitSet сам резерв 48 bytes.

Но мое требование состояло в том, чтобы хранить биты, что мне не хватает? Какие у меня варианты?

Спасибо большое

UPDATE

Мое требование, что я хочу, чтобы хранить в общей сложности 64 bits в двух отдельных областях

class MyClass{ 
    BitSet timeStamp 
    BitSet id 
} 

и я хочу, чтобы хранить миллионы MyClass объектов в памяти

+0

Сколько бит нужно хранить? Если миллионы, то накладные расходы 48 байт пренебрежимо мал против фактических сохраненных бит. Если бы только несколько, вы могли бы просто использовать int или длинный или несколько longs или long []. – assylias

+0

Вы забыли указать, сколько бит вы хотите сохранить. Самый дешевый способ хранения «бит» находится внутри примитивного типа, например. int = 32 бит. То, что вы воспринимаете как много накладных расходов в BitSet, не составляет многого, если вам нужно хранить много бит (тысячи или более). – Durandal

+0

Просто обновите требование. спасибо, что упомянул об этом – daydreamer

ответ

2

Это подводит к 45 + 3 байта (заполнение, чтобы достичь кратной 8) Это означает, что само по себе пустой BitSet оставляет 48 байт.

Прежде всего, я хочу посоветовать правильный инструмент для анализа схем компоновки объектов в 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 байт, включая долгий массив. Чтобы оптимизировать объем памяти, вы можете написать свою собственную реализацию BitSet. Например, в вашем случае использования доступны следующие опции:

public class MyOwnBitSet { 
    long word1; 
    long word2; 
} 

public class MyOwnBitSet2 { 
    long[] word = new long[2]; 
} 

public class MyOwnBitSet3 { 
    int index; 
} 

JOL производит следующий результат:

[email protected] object externals: 
      ADDRESS  SIZE TYPE             PATH       VALUE 
     76ea4c7f8   32 MyOwnBitSet        (object) 


[email protected] object externals: 
      ADDRESS  SIZE TYPE             PATH       VALUE 
     76ea53800   16 MyOwnBitSet2        (object) 
     76ea53810   32 [J              .word       [0, 0] 


[email protected] object externals: 
      ADDRESS  SIZE TYPE             PATH       VALUE 
     76ea5c070   16 MyOwnBitSet3        (object) 

Поясню последний пример MyOwnBitSet3. Чтобы уменьшить площадь памяти, вы можете предварительно выделить огромный массив объектов long/int и сохранить только указатель в правой ячейке. При достаточно большом числе объектов этот вариант является наиболее выгодным.

+0

отличная проницательность @ Иван, спасибо большое. 'MemOwnBitSet3' не соответствует моим требованиям, потому что мне нужно генерировать' ID (timestamp, uniqueId) 'непрерывно, thile' timestamp' - это то, что я могу получить от 'System.nanoTime',' uniqueId' будет для однозначной идентификации машины. – daydreamer

4

Мое требование, что я хочу, чтобы хранить в общей сложности 64 битов в двух отдельных полей

Так просто использовать длинные (64 разрядное целое число). И просто используйте это как поле бит. Я когда-то нужно что-то вроде этого, но 32 бит был достаточно для меня, поэтому написал небольшой класс библиотеки использовать Int в качестве набора бит: https://github.com/claudemartin/smallset

Feel бесплатно раскошелиться его и просто заменить ИНТ на длинные, 32 по 64, 1 по 1 л и т.д.

0

Чтобы сохранить в общей сложности 64 бит в объекте можно сделать

class MyClass{ 
    int timeStamp 
    int id 
} 

или если вы не хотите, чтобы над головой объекта вы можете сделать

long timeStampAndId; 

Проблема заключается в том как инкапсулировать ваши операции. Для примитива. Java не очень помогает, но то, что вы можете сделать, это

enum TimeStampAndId { 
    /* no instances */ ; 
    public static boolean isTimeStampSet(long timeStampAndId, int n) { ... } 
    public static boolean isIdSet(long timeStampAndId, int n) { ... } 

i.e использовать класс утилиты для поддержки примитивного типа.

В будущем Java будет поддерживать типы значений, которые не будут обладать объектными издержками.