RFR: 8056240: Investigate increased GC remark time after class unloading changes in CRM Fuse
Coleen Phillimore
coleen.phillimore at oracle.com
Fri Oct 10 20:54:03 UTC 2014
Hi Stefan,
Thank you for your patience. Some review comments:
http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/classfile/metadataOnStackMark.hpp.udiff.html
Why is there all this code here? In order to make this parallel, can
you just not have simply a GrowableArray per thread? I don't see the
purpose of all this complexity in this place. Is it trying to add as
chunked list? Can we add a utility for this instead of tying it to the
MetadataOnStackMark functionality?
In this file, what is _doit and why? This looks really strange. Can
you add a comment why sometimes doit is false and sometimes doit is
true? Is there a way to encapsulate this in a function as it's supposed
to be a scoped object.
The MetadataOnStackMark object needs to go around the calls to
purge_previous_versions and free_deallocate_list. It doesn't have to be
around the whole walk of the CLDG, it just started out that way and has
gotten more complicated. If you add it to the end like:
void ClassLoaderDataGraph::clean_metaspaces() {
// mark metadata seen on the stack and code cache so we can delete
unneeded entries.
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack(has_redefined_a_class);
if (has_redefined_a_class) {
// purge_previous_versions also cleans weak method links. Because
// one method's MDO can reference another method from another
// class loader, we need to first clean weak method links for all
// class loaders here. Below, we can then free redefined methods
// for all class loaders.
for (ClassLoaderData* data = _head; data != NULL; data =
data->next()) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
}
// Need two loops.
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->free_deallocate_list();
}
}
And only call it at the end of do_unloading this would work (I've tested
this)
if (has_metadata_to_deallocate) {
clean_metaspaces();
}
has_metadata_to_deallocate is generally true because of lambda constant
pools.
http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp.udiff.html
+ if (JvmtiExport::has_redefined_a_class()) {
+ InstanceKlass::purge_previous_versions(ik);
+ }
purge previous versions requires the on_stack bits to be set. Is this
true here? It seems very far away from the other code to me to be able
to tell. Why can't this go in the same place as the free_deallocate_lists?
http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/code/nmethod.cpp.udiff.html
I really don't like that the on-stack bit marks are done at the same
time as clean_ic_if_metadata_is_dead. They are for different
purposes. Also, this seems to mark metadata for methods that are
unloaded as well as ones that survive unloading. I guess this wouldn't
prevent methods from being unloaded but seems unnecessary callbacks to
mark_on_stack. Maybe I'm not reading this right though. I thought you
couldn't do the unloading walk with the mark-on-stack walk? Also, we
actually only have to mark OLD methods in the code cache which would
greatly reduce the callbacks. I could make this in a separate change as
I have this change in a private repository.
I think you should have a compiler reviewer comment on the nmethod code
though.
http://cr.openjdk.java.net/~stefank/8056240/webrev.00/src/share/vm/utilities/accessFlags.cpp.udiff.html
I don't know why this needs to be different than the atomic_set_bits
function. I should have made on_stack be a flag in Method* rather than
in access flags.
There's a lot here. I'm glad it helps performance and making the code
cache walk parallel is a really good change.
Thanks,
Coleen
On 10/2/14, 6:53 AM, Stefan Karlsson wrote:
> Hi all,
>
> (The following patch changes HotSpot code in areas concerning GC, RT,
> and Compiler. So, it would be good to get reviews from all three teams.)
>
> Please, review this patch to optimize and parallelize the CodeCache
> part of MetadaOnStackMark.
>
> G1 performance measurements showed longer than expected remark times
> on an application using a lot of nmethods and Metadata. The cause for
> this performance regression was the call to
> CodeCache::alive_nmethods_do(nmethod::mark_on_stack); in
> MetadataOnStackMark. This code path is only taken when class
> redefinition is used. Class redefinition is typically used in
> monitoring and diagnostic frameworks.
>
> With this patch we now:
> 1) Filter out duplicate Metadata* entries instead of storing a
> Metadata* per visited metadata reference.
> 2) Collect the set of Metadata* entries in parallel. The code
> piggy-backs on the parallel CodeCache cleaning task.
>
> http://cr.openjdk.java.net/~stefank/8056240/webrev.00/
> https://bugs.openjdk.java.net/browse/JDK-8056240
>
> Functional testing:
> JPRT, Kitchensink, parallel_class_unloading, unit tests
>
> Performance testing:
> CRM Fuse - where the regression was found
>
> The patch changes HotSpot code in areas concerning GC, RT, Compiler,
> and Serviceability. It would be good to get some reviews from the
> other teams, and not only from the GC team.
>
> thanks,
> StefanK
More information about the hotspot-dev
mailing list