JDK-8292818 changed how field metadata (e.g. access flags) is accessed to streaming access. That means accessing a field of a InstanceKlass by index has to go through the stream to find the appropriate field.
This causes a performance regression in jcmd GC.heap_dump, which uses FieldStream from reflectionUtils.hpp. This implementation has two flaws in combination with the change from JDK-8292818:
1. It uses field indexes to access data, e.g. _klass->field_access_flags(_index) to get a field's access flags.
2. It traverses the fields in reverse order. The way how the metadata is stored now only allows for efficient forward traversal.
As an example, running the attached Java file and creating a heap dump takes (on my machine):
- 2-3 seconds on Java 17
- ~20 seconds on Java 21
FieldStream cannot directly be replaced by the implementations from fieldStreams.hpp because it additionally traverses supertypes.
The proposed fix is to add field streaming with supertype traversal to fieldStreams.hpp. This way, other usages of FIeldStream are unaffected in behavior. The new implementation does foward traversal over the fields but keeps the order in which supertypes visited from FieldStream. This way, the produced heap dump will still conform to the hprof format.
Relevant mailing list discussion: https://mail.openjdk.org/pipermail/serviceability-dev/2023-October/051571.html