-
Bug
-
Resolution: Fixed
-
P3
-
11, 12, 13, 14
-
b21
The attached test (v4) shows that C2 scalar replacement (-XX:+EliminateAllocations) can prevent JVMTI
agents from finding a memory leak using JVMTI FollowReferences().
The required JVMTI capability can_tag_objects is an 'always' capability, meaning an agent can
request it during the live phase. This allows for loading an agent dynamically into the vm to do heap
diagnostics. Therefore it is not sufficient to disable scalar replacement when can_tag_objects is
taken by an agent. The test shows this also.
This bug report duplicatesJDK-8230956, but it is supposed to be less theoretical giving an example
that is close to real world scenarios and it shows, that just disabling escape analysis is not
sufficient.
Steps performed by the test:
// Please use v4. Previous versions are obsolete.
- Warmup: call dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) often with small
leak size to get it compiled by C2.
- After warmup call dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) again with
Long.MAX_VALUE as target leak size.
- In that call create and inflate a new leak, linking new LeakObject instances into a list which is
rooted at an object referenced by the local variable 'holder'.
- This 'holder' object is allocated at the entry of dontinline_leakHoldingMethodWithScalarReplacement(long leakSize).
C2 eliminated this allocation based on proof by escape analysis that the created object is local
to the compiled method. The scalar field values are used directely be the compiled code (scalar replacement).
- Continue inflating until until {@link OutOfMemoryError} is thrown.
- Catch the OOM in {@link #dontinline_allocateNewLeakObj()} and dynamically load the agent to create
a class histogram of reachable heap objects. This can be done, because the capability
can_tag_objects required for JVMTI FollowReferences() can be added during the live phase.
- Call into the agent which uses JVMTI FollowReferences() to sum up used bytes per class of
reachable objects. The implementation of FollowReferences() misses scalar replaced objects and
consequently all leaked objects too.
- Control returns to dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) and an uncommon trap is hit.
- The compiled frame is replaced with interpreter frames. Scalar replaced objects are reallocated on the heap.
- Capture 2nd class histogram. This one shows the leak, because the holder was reallocated on the heap.
- Store the root object 'holder' into a static variable. Because of this store the holder object was and is
"definitively reachable" in the sense of JLS 12.6 Finalization of Class Instances.
- Capture 3nd class histogram. It contains the leak as well.
- Delete reference to the leak.
- Capture 4th class histogram. It shows that the leak became unreachable.
agents from finding a memory leak using JVMTI FollowReferences().
The required JVMTI capability can_tag_objects is an 'always' capability, meaning an agent can
request it during the live phase. This allows for loading an agent dynamically into the vm to do heap
diagnostics. Therefore it is not sufficient to disable scalar replacement when can_tag_objects is
taken by an agent. The test shows this also.
This bug report duplicates
that is close to real world scenarios and it shows, that just disabling escape analysis is not
sufficient.
Steps performed by the test:
// Please use v4. Previous versions are obsolete.
- Warmup: call dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) often with small
leak size to get it compiled by C2.
- After warmup call dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) again with
Long.MAX_VALUE as target leak size.
- In that call create and inflate a new leak, linking new LeakObject instances into a list which is
rooted at an object referenced by the local variable 'holder'.
- This 'holder' object is allocated at the entry of dontinline_leakHoldingMethodWithScalarReplacement(long leakSize).
C2 eliminated this allocation based on proof by escape analysis that the created object is local
to the compiled method. The scalar field values are used directely be the compiled code (scalar replacement).
- Continue inflating until until {@link OutOfMemoryError} is thrown.
- Catch the OOM in {@link #dontinline_allocateNewLeakObj()} and dynamically load the agent to create
a class histogram of reachable heap objects. This can be done, because the capability
can_tag_objects required for JVMTI FollowReferences() can be added during the live phase.
- Call into the agent which uses JVMTI FollowReferences() to sum up used bytes per class of
reachable objects. The implementation of FollowReferences() misses scalar replaced objects and
consequently all leaked objects too.
- Control returns to dontinline_leakHoldingMethodWithScalarReplacement(long leakSize) and an uncommon trap is hit.
- The compiled frame is replaced with interpreter frames. Scalar replaced objects are reallocated on the heap.
- Capture 2nd class histogram. This one shows the leak, because the holder was reallocated on the heap.
- Store the root object 'holder' into a static variable. Because of this store the holder object was and is
"definitively reachable" in the sense of JLS 12.6 Finalization of Class Instances.
- Capture 3nd class histogram. It contains the leak as well.
- Delete reference to the leak.
- Capture 4th class histogram. It shows that the leak became unreachable.
- duplicates
-
JDK-8230956 Should disable Escape Analysis when JVMTI capability can_tag_objects is taken
-
- Closed
-
-
JDK-8230956 Should disable Escape Analysis when JVMTI capability can_tag_objects is taken
-
- Closed
-
- relates to
-
JDK-8227745 Enable Escape Analysis for Better Performance in the Presence of JVMTI Agents
-
- Resolved
-
-
JDK-8285739 disable EscapeBarrier deopt for virtual threads
-
- Resolved
-
(1 links to)