When I have to worry about bit packing I often keep the data out of line (i.e. not in the object (in fact the object may not even have contiguous storage at all). This can improve object packing (how much you can get in RAM, cache line impact, etc).
Here's a contrived example (I don't work in e-commerce): let's say I have a boolean to indicate if a user is a premium customer. I don't care about that when they are buying something but marketing wants the info to send them special offers and such.
Define the customer record this way (sorry, this is C++; haven't used Java in a while):
class cust {
private:
int id;
string name;
public:
auto get_id() { return id; }
auto get_name() { return name; }
auto get_is_customer();
}
Then store the is_customer info in a vector of ints, indexing off the customer id.
This takes up a lot less space, and in fact most of the time the is_customer info need not even be fetched from storage; it's only needed when marketing is running a non-time-critical function.
One nice thing is that a refactor like this is transparent to the call sites (at a source code level -- you still have to recompile)
You can do further speed ups, for example storing name/address info out-of-object since it's only needed when completing the order (just pre-fetch it when the user views the shopping cart).
Realistically this is silly for this e-commerce example where you just fetch from your SQL database and have different bottlenecks to worry about.
But until recently I was working on symbolic computing with neural networks; it mattered a lot to get a lot of the working set into core, yet different algos were looking at different parts of the objects. In fact this approach made it easier to parallelize some computation. It also made streaming data through transforms a lot faster.
Hopefully Project Valhalla will make this easier :)
JEP 218 (Generics over Primitive Types)[0] allowing Map<Key, int> without the performance penalty of boxing, and the Value Objects JEP[1] allowing the record in the example to become a value type.
> Fortunately, there are several open-source libraries, that offer storing keys and values which allow storing keys and values as primitive values, without boxing:
fastutil,
agrona,
koloboke.
> In production, we use fastutil, because, based on our internal benchmarks, it shows better performance for read and write operations.
I wonder how they arrived at this shortlist to test. I'd only heard of fastutil along with many not on this list (Trove, HPPC, CERN Colt, FastUtil, Joda Primitives, Eclipse Collections). Maybe agrona and koloboke are newer. The next time I need something similar I'll check them out.
Here's a contrived example (I don't work in e-commerce): let's say I have a boolean to indicate if a user is a premium customer. I don't care about that when they are buying something but marketing wants the info to send them special offers and such.
Define the customer record this way (sorry, this is C++; haven't used Java in a while):
Then store the is_customer info in a vector of ints, indexing off the customer id.This takes up a lot less space, and in fact most of the time the is_customer info need not even be fetched from storage; it's only needed when marketing is running a non-time-critical function.
One nice thing is that a refactor like this is transparent to the call sites (at a source code level -- you still have to recompile)
You can do further speed ups, for example storing name/address info out-of-object since it's only needed when completing the order (just pre-fetch it when the user views the shopping cart).
Realistically this is silly for this e-commerce example where you just fetch from your SQL database and have different bottlenecks to worry about.
But until recently I was working on symbolic computing with neural networks; it mattered a lot to get a lot of the working set into core, yet different algos were looking at different parts of the objects. In fact this approach made it easier to parallelize some computation. It also made streaming data through transforms a lot faster.