3 ms·
Why are there so many unused bits in the header in the first place? 12% heap size reduction across the board sounds really nice but I feel like some historical
by maxfurman 4y ago
Why are there so many unused bits in the header in the first place? 12% heap size reduction across the board sounds really nice but I feel like some historical context on the original design is missing.
- nayuki 4y agoProbably for alignment. You want the class pointer (whether 32- or 64-bit) to be easy to dereference with little or no preprocessing. It looks like the HotSpot JVM implementers decided to use 5 bits for lock and GC, and 31 bits for identity hash code (not sure why they didn't use 32). That adds up to 36 bits. You'd want to round this up to a multiple of 32 bits so that both the beginning of the object and the class pointer are aligned to 32 or 64 bits.
- origin_path 4y agoIf you look at the tricks needed to shrink it to 64 bits then you'll see why this is hard. Consider that this object header has to contain: - GC state bits. - The class metadata, i.e. pointer to a Class<> object. - Lock data, including possibly a pointer to a lock. - Possibly, an identity hash code. - Possibly, a GC forwarding pointer. Several of these are pointers! If you're on a 64 bit machine, just one* of them implemented naively if immediately 64 bits. In other words Java object headers provide a lot of stuff. To pack the whole thing down to just 64 bits requires a lot of clever implementation tricks, exploiting what exact combinations can appear, etc. Also note that this overhead isn't Java specific. In C++ you have malloc headers and then the C++ vtable pointer, in many cases. So just running "new SomeObj()" in C++ will immediately blow you past the heap overhead of Java after this JEP is merged, and if you need to add a lock and/or reference count to catch up with the Java feature set then you're at multiples of it.
- yakubin 4y ago1. C++ doesn’t use vtables for classes which do not have virtual methods (in practice most of them). And vtables are shared between objects of the same type. 2. “Malloc headers”? Malloc usually stores metadata in freed data. 3. C++ developers don’t call “new” for every single object, the way Java devs do. Idiomatic code defaults to allocating fixed-size objects inline (on stack or in a pre-existing bigger allocation), not in a separate allocation. 4. In C++ there are other ways to allocate dynamic memory than “new”. Arena allocators, directly calling mmap/VirtualAlloc/whatever makes sense in a given case.
- origin_path 4y agoYes, I know C++, I didn't say that's the only way to allocate objects in C++, just that if you do write a heap allocated object that has virtual methods (a pretty common thing to want to do), then the metadata for that will be larger than 64 bits. Your malloc storing metadata non-adjacent to the allocation doesn't change the fact that there is some, and it has to be stored.
- chrisseaton 4y agoWhat would you have put in them instead? If you can't think of anything... then probably nobody could think of anything either.
- twic 4y agoThe header traditionally contains: 1. a pointer to the class 2. the object's lock 3. some GC bits 4. the identity hash code In a naive implementation, the class pointer is a machine word, the lock is multiple machine words, the GC bits are a few bits, which get rounded up to a word for alignment, and the hash is 32 bits. Object headers used to be even bigger than 128 bits! There have been improvements: compress the class pointer, use a lazily-inflated lock which takes up only one word in the header, make the identity hash smaller, and make the lock and the identity hash share space (when the lock is deflated, the identity hash lives in the shared slot; when the lock is inflated, the slot has a pointer to a lock structure which also contains the identity hash). The change in this JEP is effectively to extend the inflation-dependent space sharing scheme to include the class pointer too. When the lock is deflated, the header contains the class pointer and the identity hash; when it is inflated, it is a pointer to the lock structure, which contains the class pointer and identity hash. I suppose this means that virtual method calls through a locked object will involve an additional indirection - but this should be rather easy for a compiler to optimise, because it can safely hoist the loading of the class pointer.