Normal usage of this stuff is not going to cause any more issues than trigger the OCD of people that obsess about this stuff. And in the rare case that you do have an issue, you can do something more optimal indeed.
Normal usage of this stuff is not going to cause any more issues than trigger the OCD of people that obsess about this stuff. And in the rare case that you do have an issue, you can do something more optimal indeed.
Collections in Java as of now (before project Valhalla) are actually collections of pointers to objects, so at least one level of indirection. Another level of indirection is List itself, which is an interface, so the compiler can’t ahead of time devirtualise method calls, only after JIT detects which List implementation it’s dealing with at runtime.
What this means is that in practice, pointer chasing is less of an issue than you’d expect. Even a linked list will end up with decent cache locality.
Obviously this won’t always work, but it generally works a lot better than the same structure in a systems language.
https://shipilev.net/jvm/anatomy-quarks/11-moving-gc-localit...
You can get away with referencing the data through (mutable and reusable) pointer objects that reference memory mapped areas yet provide a relatively comfortable higher level interface. This gets rid of object churn while keeping a relatively sane interface.
But a very bare bones example might look something like
class MdrLayout {
static final int FOO_OFFSET = 0;
static final int BAR_OFFSET = 4;
static final int BAZ_OFFSET = 12;
static final int ENTRY_SIZE = 13;
}
class MyDataRecord {
int idx = Integer.MIN_VALUE;
ByteBuffer buffer = null;
MyDataRecord() { }
void movePointer(ByteBuffer buffer, int idx) {
this.buffer = buffer;
this.idx = idx;
}
int foo() { return buffer.getInt(ENTRY_SIZE * idx + FOO_OFFSET); }
long bar() { return buffer.getLong(ENTRY_SIZE * idx + BAR_OFFSET); }
byte baz() { return buffer.get(ENTRY_SIZE * idx + BAZ_OFFSET); }
// may have operators like reset(), next() or skip() as well
}
or class MyDataRecord2 {
final ByteBuffer buffer;
MyDataRecord2(ByteBuffer buffer) { this.buffer = buffer; }
int foo(int idx) { return buffer.getInt(ENTRY_SIZE * idx + FOO_OFFSET); }
long bar(int idx) { return buffer.getLong(ENTRY_SIZE * idx + BAR_OFFSET); }
byte baz(int idx) { return buffer.get(ENTRY_SIZE * idx + BAZ_OFFSET); }
}There are plenty of fast performing databases and other middleware written in Java. The JVM is a popular platform for that kind of thing for a good reason. Writing good software of course is a bit of a skill. Benchmarks like this are kind of pointless. Doing an expensive thing in a loop is slow. Well duh. Don't do that.