Hacker News new | past | comments | ask | show | jobs | submit login
Why and how we use primitive maps (trivago.com)
22 points by skilled on March 26, 2022 | hide | past | favorite | 5 comments



I think the busy loop version can use Thread.onSpinWait() to improve performance if the tryLock fails.

[1] https://docs.oracle.com/en/java/javase/17/docs/api/java.base...()


Indeed, although userspace spinlocks are almost always a bad idea, it's possible to write a much better one than repurposing ReadWriteLock.

1. As you say, use onSpinWait

2. It emits a load barrier on each failed trylock call, from the underlying strong integer CAS. Ideally it would use a cas with relaxed memory order, and use an acquire fence only if successful.

3. The read path emits store barriers on release, which is unnecessary. Releasing could use a relaxed order fetch-add instruction.

It's theoretically possible that the JIT would be smart enough to optimize these with the existing code, but that's asking a lot from its analysis, including that the thread local storage writes for detecting reentrance aren't "real" writes that need to be made visible to other threads.


Interesting. I don't have anything to add to this, but by a very strange coincidence I was working on exactly the same things as this article describes today - packing smaller fields into an integer with bitwise operations and using the primitive maps in fastutil.


Is this saying every Java object (struct?) has 16 bytes of storage overhead? Does that apply to arrays of objects too?


Yes, in 64-bit HotSpot every object has a 16-byte header, and it applies to arrays if by that you mean that each object in an array still has a header. There's a good overview of what that space is used for here:

https://wiki.openjdk.java.net/display/lilliput/Main




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: