RFR (L) 8061205: MetadataOnStackMark only needs to walk code cache during class redefinition

Coleen Phillimore coleen.phillimore at oracle.com
Wed Mar 11 20:48:22 UTC 2015


Stefan,

I made the changes you suggested.  I also moved purge_previous_versions 
conditionally back to class unloading, where G1 doesn't do this until 
full GC.   Do you prefer this to calling the separate function for 
ClassLoaderDataGraph::clean_redefinition_metadata()?  I thought with a 
separate function we could be more judicious where to call it, but we 
can also add conditions to ClassLoaderDataGraph::do_unloading() to avoid 
metadata walking.

http://javaweb.us.oracle.com/~cphillim/webrev/8061205.03/

I've rerun all the class redefinition tests with -XX:+UseG1GC and with 
the default collector.

Thanks,
Coleen

On 3/10/15, 3:50 PM, Coleen Phillimore wrote:
>
> Stefan,   Thank you for reviewing this so quickly!
>
> On 3/10/15, 12:24 PM, Stefan Karlsson wrote:
>> Hi Coleen,
>>
>> Thanks for fixing this and lowering the G1 remark times when class 
>> redefinition is used.
>>
>> I'm only reviewing the GC specific parts:
>>
>> On 2015-03-09 21:57, Coleen Phillimore wrote:
>>> Summary: Only do full metadata walk during class redefinition and 
>>> only walk handles during class unloading.
>>>
>>> This change decouples metadata walking for redefinition and class 
>>> unloading, so that class unloading for G1 doesn't walk the code 
>>> cache.  It also decouples GC and on_stack marking in the code cache.
>>>
>>> open webrev at http://cr.openjdk.java.net/~coleenp/8061205/
>>
>>
>> http://cr.openjdk.java.net/~coleenp/8061205/src/share/vm/classfile/metadataOnStackMark.cpp.frames.html 
>>
>>
>> There are Atomic calls left to handle concurrent retiring of buffers. 
>> Do you want to keep it?:
>
> I didn't know whether I should or not.  I suppose we should trust our 
> source code control system in case we ever need to do this 
> concurrently again.  I'll remove the concurrency - it makes the code a 
> bit simpler.   The code to do chunked lists is still good though, so 
> I'm glad you added that as a utility class.
>>
>>   97 void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* 
>> buffer) {
>>   98   if (buffer == NULL) {
>>   99     return;
>>  100   }
>>  101
>>  102   MetadataOnStackBuffer* old_head;
>>  103
>>  104   do {
>>  105     old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers);
>>  106     buffer->set_next_used(old_head);
>>  107   } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) 
>> != old_head);
>>  108 }
>>
>> There's also some Atomic code in accessFlags that were added to 
>> support concurrent mark_on_stack calls. Maybe you want to get rid of 
>> that code as well?
>
> I like how you changed it so that the cpool and method is only 
> recorded if it's not already marked.  That probably saves a lot of 
> time and space.
>>
>>
>> http://cr.openjdk.java.net/~coleenp/8061205/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp.cdiff.html 
>>
>>
>> Could you get rid of the pre/post_work_verification functions? They 
>> were only added to be able to verify the MetadataOnStackMark state, 
>> and is not needed anymore.
>>
>>     void pre_work_verification() {
>> - 
>> assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should 
>> be empty");
>>     }
>>       void post_work_verification() {
>> - 
>> assert(!MetadataOnStackMark::has_buffer_for_thread(Thread::current()), "Should 
>> be empty");
>>     }
>>
>>
>
> Okay, thanks.  I didn't know if you'd prefer that.
>
>>
>> http://cr.openjdk.java.net/~coleenp/8061205/src/share/vm/runtime/thread.cpp.frames.html 
>>
>>
>> 4105 void Threads::metadata_handles_do(void f(Metadata*)) {
>> 4106   // Only walk the Handles in Thread.
>> 4107   ALL_JAVA_THREADS(p) {
>> 4108     p->metadata_handles_do(f);
>> 4109   }
>> 4110 }
>>
>> This only walks metadata handles in the Java threads. Don't we have 
>> metadata handles in the VM  Thread?
>>
>>
>
> Hm.   We never walked non-Java threads before but yes, we could have 
> Metadata handles on these threads.  Wow, thanks for finding this 
> bug!   I think this should walk GC threads too (no?)
>
>>
>> http://cr.openjdk.java.net/~coleenp/8061205/src/share/vm/gc_implementation/shared/vmGCOperations.cpp.frames.html 
>>
>>
>> Could you motivate why only Metadata induced Full GCs need to do this 
>> unloading?
>>
>>  268   // If redefinition, make a pass over the metadata to find any 
>> that
>>  269   // can be marked to be deallocated
>>  270   if (JvmtiExport::has_redefined_a_class()) {
>>  271     ClassLoaderDataGraph::clean_redefinition_metadata();
>>  272   }
>>
>> Don't we need it for our other Full GCs?
>
> No, I don't think we want it for all full GCs.   The effect of 
> cleaning out the redefinition metadata is to remove the metadata 
> itself.  There may be some mirrors unused from the redefined classes.  
> I suppose you could construct a test case where one of the mirrors is 
> gigantic and causes an out of memory situation in Java heap.
>
> The main effect of walking the previous versions is to find more 
> metadata to clean out though, for the next attempt at class unloading.
>>
>> I would prefer if this code could be kept inside the GC code or where 
>> it used to be, inside the ClassLoaderDataGraph::do_unloading 
>> function. With the current change, the 
>> VM_CollectForMetadataAllocation class is burdened with the internal 
>> knowledge about class redefinition and class unloading.
>
> In ClassLoaderDataGraph::do_unloading() is used when you're not in a 
> Full GC, which is the problem.  It can't go there unless we pass down 
> the logic that we're in a full GC or not.  I think this is messier.  I 
> think this VM_CollectForMetadataAllocation seems the right place to 
> clean up metadata, if needed.   One place or another, there has to be 
> knowledge of class redefinition.
>
> Actually, my original change had it not called at all, since this code 
> is executed for every class redefinition.  Then I thought something 
> should call it...   The bias should be to avoid calling this function 
> though because generally it doesn't find very much to do.
>
> I thought a better place to call this would be for last-ditch 
> collections, but I didn't know exactly where that was.
>
> Coleen
>>
>> Thanks,
>> StefanK
>>
>>> bug link https://bugs.openjdk.java.net/browse/JDK-8061205
>>>
>>> Tested with FMW performance runs. vm.quick.testlist, 
>>> jdk/test/java/lang/instrument tests and JPRT.
>>>
>>> Thanks,
>>> Coleen
>>
>



More information about the hotspot-dev mailing list