-
Enhancement
-
Resolution: Fixed
-
P4
-
17, 20, 21
-
b20
One of our application stacks apparently benefits from changing Enum.hashCode calls to Enum.ordinal calls in some composite hashCode calculations. There is at least one relevant report that asks to do the same, see JDK-8050217.
Changing the hash code characteristics is not something we do lightly, and it needs to have a solid reason to do so. But we can micro-optimize current Enum.hashCode to perform better, thus rendering the "use ordinal in lieu of hashcode for enums" suggestion much closer to being moot performance-wise.
Performance investigation shows that Enum.hashCode is not very fast right now, because it has to pull the identity hash code from the object header, mask it out to recover the hash, check it is initialized, call the slowpath when it is not initialized, or is in displaced header, etc. With more work towards compact object headers, the cost of accessing identity hashcode would likely to become even greater.
Fortunately, there is a space at least in field-less Enums to cache the hashcode directly. There is a precedent of doing the same for Strings.
% java -jar jol-cli-latest.jar internals java.lang.Enum
# VM mode: 64 bits
# Compressed references (oops): 3-bit shift
# Compressed class pointers: 3-bit shift
# Object alignment: 8 bytes
# ref, bool, byte, char, shrt, int, flt, lng, dbl
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array base offsets: 16, 16, 16, 16, 16, 16, 16, 16, 16
Failed to find matching constructor, falling back to class-only introspection.
java.lang.Enum object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) N/A
8 4 (object header: class) N/A
12 4 int Enum.ordinal N/A
16 4 java.lang.String Enum.name N/A
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Also, since the enum constants are singletons, even if this increases the size of the enum instance in other configurations or for enums having more fields, the memory loss for such caching would be minimal. If we cache the hash code at use, we also dodge the startup costs, if any. Although, we can also initialize the hash eagerly, and then Enum.hashCode would be exactly like Enum.ordinal performance-wise.
Changing the hash code characteristics is not something we do lightly, and it needs to have a solid reason to do so. But we can micro-optimize current Enum.hashCode to perform better, thus rendering the "use ordinal in lieu of hashcode for enums" suggestion much closer to being moot performance-wise.
Performance investigation shows that Enum.hashCode is not very fast right now, because it has to pull the identity hash code from the object header, mask it out to recover the hash, check it is initialized, call the slowpath when it is not initialized, or is in displaced header, etc. With more work towards compact object headers, the cost of accessing identity hashcode would likely to become even greater.
Fortunately, there is a space at least in field-less Enums to cache the hashcode directly. There is a precedent of doing the same for Strings.
% java -jar jol-cli-latest.jar internals java.lang.Enum
# VM mode: 64 bits
# Compressed references (oops): 3-bit shift
# Compressed class pointers: 3-bit shift
# Object alignment: 8 bytes
# ref, bool, byte, char, shrt, int, flt, lng, dbl
# Field sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8
# Array base offsets: 16, 16, 16, 16, 16, 16, 16, 16, 16
Failed to find matching constructor, falling back to class-only introspection.
java.lang.Enum object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) N/A
8 4 (object header: class) N/A
12 4 int Enum.ordinal N/A
16 4 java.lang.String Enum.name N/A
20 4 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
Also, since the enum constants are singletons, even if this increases the size of the enum instance in other configurations or for enums having more fields, the memory loss for such caching would be minimal. If we cache the hash code at use, we also dodge the startup costs, if any. Although, we can also initialize the hash eagerly, and then Enum.hashCode would be exactly like Enum.ordinal performance-wise.
- relates to
-
JDK-8333791 Fix memory barriers for @Stable fields
- Resolved
-
JDK-8050217 Enum.hashCode() should return ordinal value for the enum, for better consistency
- Closed