-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8266936: Add a finalization JFR event #4731
Conversation
👋 Welcome back mgronlun! A progress list of the required criteria for merging this PR into |
/label core-libs |
@mgronlun |
Webrevs
|
@@ -1081,6 +1081,10 @@ | |||
<Field type="uint" name="stallCount" label="Stall Count" description="The number of Java threads stalled by the GC locker" /> | |||
</Event> | |||
|
|||
<Event name="Finalizer" category="Java Application" label="Finalizer" thread="false" startTime="false" period="endChunk"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense for this event to be under the "Java Virtual Machine, GC" category?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My argument for placing the event in the Java Application category:
The finalization concept is, or maybe more correctly has been, reified in the Java language. The Java programmer decides to enlist the exposed functionality, similar to Java language Exceptions and Errors. JFR already represents events for these latter concepts in the Java Application category because programmers directly interact with and, in contrast to many events in the JVM category, have more control over them.
This approach inspecting the loaded classes periodically as well as tracking the classes being unloaded looks good. A class with the same class name may be loaded from different class loader and could also be loaded from different code source. It'd be useful for the finalizer event to include the code source which is passed from defineClass to help identify where the class was loaded from. |
Thanks @mlchung. The JFR model has an intrinsic relation between a class and its class loader, which is persisted in the recording. The code source is not saved in the VM as part of the InstanceKlass, but one could get to the associated ProtectionDomain (if one exist) through the mirror class. The "codesource" field of the ProtectionDomain can be used to read the "locationfNoFragString" which could then be saved as a "codesource" event field. |
On 7/20/21 9:05 AM, Markus Grönlund wrote:
Thanks @mlchung
<https://urldefense.com/v3/__https://github.com/mlchung__;!!ACWV5N9M2RV99hQ!fVubB-l54eZUOlhXXwPirzkYT3g2TrNDmcdCKSoUPk1bGTkIA52FeUbMu70iiomgHQ$>.
The JFR model has an intrinsic relation between a class and its class
loader, which is persisted in the recording.
The code source is not saved in the VM as part of the InstanceKlass,
but one could get to the associated ProtectionDomain (if one exist)
through the mirror class. The "codesource" field of the
ProtectionDomain can be used to read the "locationfNoFragString" which
could then be saved as a "codesource" event field.
It's also passed to JVM_DefineClassWithSource [1] at define class time.
It may be another place to obtain the info.
Mandy
[1]
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/prims/jvm.cpp#L1032
|
|
Mailing list message from Bernd Eckenfels on core-libs-dev: Hello, I know I am a bit late, but just wanted to mention, that since finding finalizers with Bytecode analysis is doable (and probably easier to deal with such scan reports), I don?t see much value in a JFR event, especially considering it even has native code executed. (Not so sure about dynamically loaded classes, would the event content help to identify sources?) Having said that, this event would be more useful from a runtime perspective if It would actually record execution counts and time per class. Then one can concentrate on the worst offenders, first and even use it for runtime monitoring. Is there already a finalizer profiler? Gruss
Markus Gr?nlund has updated the pull request incrementally with one additional commit since the last revision: remove build directive ------------- Changes: Webrevs: Stats: 1 line in 1 file changed: 0 ins; 1 del; 0 mod PR: https://git.openjdk.java.net/jdk/pull/4731 |
Hi, Bernd The JFR event can complement static bytecode analysis, reporting which classes with finalizers actually get loaded at runtime. I agree that it would be useful to add a count for finalizers that get run, either as part of this PR, or as a follow-up. I would hesitate to add timing, though. It's important to keep the overhead of this event low, and finalize() methods should already show up in current profilers. Thanks,
|
/label remove hotspot-jfr |
/label remove core-libs |
@mgronlun |
@mgronlun |
Sorry for the wide distribution, but this became necessary as the PR touches many component areas, if only some with minor parts. Below is a high-level description of this suggested PR. // Design Allocation of an object with a class overriding finalize() with a non-empty finalize() method is hooked by the runtime using bytecode "_return_register_finalizer", which has it enter InstanceKlass::register_finalizer(). The dedicated finalizer thread is responsible for running the finalizer methods for referent objects whose java.lang.ref.Finalizers have been enqueued for finalization by the GC. Class Unloading support is in place by adding a hook in SystemDictionary::do_unloading(). The existing JFR class unloading support is extended to also report a FinalizerStatistic event for the class being unloaded before its corresponding FinalizerEntry is purged from the FinalizerService implementation table. -Xlog:finalize is added for Unified Logging support. // JFR event output jdk.FinalizerStatistics: Event:jdk.FinalizerStatistics { // Xlog:finalizer output: // Misc ClassLoadingService - some parts needed to have better conditional compilation and runtime support for running the JVM when excluding JVM feature 'management'. jmm.h - is a private interface between the JVM and the JDK, so a CSR should not be necessary for the update and version change. // Performance The reporting back to the VM on finalization complete is performed only by the dedicated FinalizerThread. It introduces some additional work, but work performed by the FinalizerThread is not considered performance-sensitive because of the indeterministic nature of when finalizers are run (if at all). // Extensibility The FinalizerEntry struct can also be extended, for example, with performance data. An attempt was made to see if it was possible to attribute CPU time as well. However, the relatively short-lived character of a typical finalize() method combined with existing thread CPU timing APIs, which proved too coarse-grained (at least on some platforms?), did not give valuable data. |
@mgronlun The label
|
@mgronlun The label
|
/label add core-libs, hotspot-jfr, hotspot-runtime, serviceability |
@mgronlun This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 52 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : | ||
_ik(ik), | ||
_objects_on_heap(0), | ||
_total_finalizers_run(0) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok.
|
||
void FinalizerService::purge_unloaded() { | ||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock); | ||
ClassLoaderDataGraph::classes_unloading_do(&on_unloading); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see - grow the table.
I'm not sure if you need to ask ik->is_loader_alive() or not, but I think you do. The InstanceKlass is removed from your table during class unloading but before that during concurrent class unloading, the class might not be alive while you look at it and concurrent class unloading hasn't gotten around to removing it yet. Since you save classes regardless of CLD, you have to check if it's alive. See classLoaderDataGraph.cpp ClassLoaderDataGraphIterator for example. The CLDG_lock only keeps the graph from not getting modified, but the classes in it might be dead.
|
||
void FinalizerService::purge_unloaded() { | ||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock); | ||
ClassLoaderDataGraph::classes_unloading_do(&on_unloading); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, I don't see where you return an InstanceKlass in the table, which would need this check. Not in class_unloading_do because this follows the _unloading list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing the renames. Looks good!
/integrate |
Going to push as commit 72a976e.
Your commit was automatically rebased without conflicts. |
Greetings,
Object.finalize() was deprecated in JDK9. There is an ongoing effort to replace and mitigate Object.finalize() uses in the JDK libraries; please see https://bugs.openjdk.java.net/browse/JDK-8253568 for more information.
We also like to assist users in replacing and mitigating uses in non-JDK code.
Hence, this changeset adds a periodic JFR event to help identify which classes are overriding Object.finalize().
Thanks
Markus
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/4731/head:pull/4731
$ git checkout pull/4731
Update a local copy of the PR:
$ git checkout pull/4731
$ git pull https://git.openjdk.java.net/jdk pull/4731/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 4731
View PR using the GUI difftool:
$ git pr show -t 4731
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/4731.diff