Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anyway to store bits in Java without memory overhead?

This has caught my interest and attention since yesterday. I am trying to store bits in Java and hit by Memory Overhead.

My first question regarding same is What is size of my Bitset?

Based on the answers I looked at other references and found Memory Usage guide.

Then I looked at BitSet source code which looks like

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;
    }

.....
}

As per the calculation based on Memory Guide, this is what I calculated

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

This sums to 45 + 3 bytes (padding to reach multiple of 8)

This means an empty BitSet itself reserves 48 bytes.

But my requirement was to store bits, What am I missing? What are my options here?

Thanks much

UPDATE

My requirement is that I want to store total of 64 bits in two separate fields

class MyClass{
    BitSet timeStamp
    BitSet id
}

and I want to store millions of MyClass objects in memory

like image 525
daydreamer Avatar asked Jan 31 '26 13:01

daydreamer


1 Answers

My requirement is that I want to store total of 64 bits in two separate fields

So just use long (64 bit integer). And just use that as a bit field. I once needed something like that, but 32 bit was enough for me, so wrote a little library class to use an int as a bit set: https://github.com/claudemartin/smallset

Feel free to fork it and just replace int by long, 32 by 64, 1 by 1L etc.

like image 147
Claude Martin Avatar answered Feb 03 '26 02:02

Claude Martin