RFR: 8179302: Pre-resolve constant pool string entries and cache resolved_reference arrays in CDS archive

Ioi Lam ioi.lam at oracle.com
Thu Aug 10 21:15:21 UTC 2017


Hi Jiangli,


The changes look good to me. Thanks for considering my suggestions.


- Ioi


On 8/8/17 5:33 PM, Jiangli Zhou wrote:
> Here is the incremental webrev that has all the changes incorporated 
> with suggestions from Coleen, Ioi and Thomas:
>
> http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.03.inc/ 
> <http://cr.openjdk.java.net/%7Ejiangli/8179302/webrev.hotspot.03.inc/>
>
> Updated full webrev: 
> http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.03/ 
> <http://cr.openjdk.java.net/%7Ejiangli/8179302/webrev.hotspot.03/>
>
> Thanks again for Coleen's, Ioi's and Thomas’ review!
> Jiangli
>
>> On Aug 7, 2017, at 7:57 PM, Jiangli Zhou <jiangli.zhou at Oracle.COM 
>> <mailto:jiangli.zhou at Oracle.COM>> wrote:
>>
>> Hi Ioi,
>>
>> Thanks for getting back to me.
>>
>>> On Aug 7, 2017, at 5:45 PM, Ioi Lam <ioi.lam at oracle.com 
>>> <mailto:ioi.lam at oracle.com>> wrote:
>>>
>>> On 8/4/17 10:19 PM, Jiangli Zhou wrote:
>>>
>>>> Hi Ioi,
>>>>
>>>> Thanks for looking again.
>>>>
>>>>> On Aug 4, 2017, at 2:22 PM, Ioi Lam <ioi.lam at oracle.com 
>>>>> <mailto:ioi.lam at oracle.com>> wrote:
>>>>>
>>>>> Hi Jiangli,
>>>>>
>>>>> The code looks good in general. I just have a few pet peeves for 
>>>>> readability:
>>>>>
>>>>>
>>>>> (1) stringTable.cpp and metaspaceShared.cpp have the same asserts
>>>>>
>>>>>  704 assert(UseG1GC, "Only support G1 GC");
>>>>>  705 assert(UseCompressedOops && UseCompressedClassPointers,
>>>>>  706 "Only support UseCompressedOops and 
>>>>> UseCompressedClassPointers enabled");
>>>>>
>>>>> 1615 assert(UseG1GC, "Only support G1 GC");
>>>>> 1616 assert(UseCompressedOops && UseCompressedClassPointers,
>>>>> 1617 "Only support UseCompressedOops and 
>>>>> UseCompressedClassPointers enabled");
>>>>>
>>>>> Maybe it's better to combine them into a single function like 
>>>>> MetaspaceShared::assert_vm_flags() so they don't get out of sync?
>>>>
>>>> There is a MetaspaceShared::allow_archive_heap_object(), which 
>>>> checks for UseG1GC, UseCompressedOops and 
>>>> UseCompressedClassPointers combined. It does not seem to worth add 
>>>> another separate API for asserting the required flags. I’ll use 
>>>> that in the assert.
>>>>
>>>>>
>>>>>
>>>>>
>>>>> (2) FileMapInfo::write_archive_heap_regions()
>>>>>
>>>>> I still find this code very hard to read, especially due to the loop.
>>>>>
>>>>> First, the comments are not consistent with the code:
>>>>>
>>>>>     498 assert(arr_len <= max_num_regions, "number of memory 
>>>>> regions exceeds maximum");
>>>>>
>>>>> but the comments says: "The rest are consecutive full GC regions" 
>>>>> which means there's a chance for max_num_regions to be more than 2 
>>>>> (which will be the case with Calvin's java-loader dumping changes 
>>>>> using very small heap size).So the code is actually wrong.
>>>>
>>>> The max_num_regions is the maximum number of region for each 
>>>> archived heap space (the string space, or open archive space). We 
>>>> only run into the case where the MemRegion array size is larger 
>>>> than max_num_regions with Calvin’s pending change. As part of 
>>>> Calvin’s change, he will change the assert into a check and bail 
>>>> out if the number of MemRegions are larger than max_num_regions due 
>>>> to heap fragmentation.
>>>>
>>>>
>>> Your latest patch assumes that arr_len <= 2, but the implementation 
>>> of G1CollectedHeap::heap()->begin_archive_alloc_range() / 
>>> G1CollectedHeap::heap()->end_archive_alloc_range() actually allows 
>>> more than 2 regions to returned. So simply putting an assert there 
>>> seems risky (unless you have analyzed all possible scenarios to 
>>> prove that's impossible).
>>>
>>> Instead of trying to come up with a complicated proof, I think it's 
>>> much safer to disable the archived string region if the arr_len > 2. 
>>> Also, if the string region is disabled, you should also disable the 
>>> open_archive_heap_region
>>>
>>> I think this is a general issue with the mapped heap regions, and it 
>>> just happens to be revealed by Calvin's patch. So we should fix it 
>>> now and not wait for Calvin's patch.
>>
>> Ok. I’ll change the assert to be a check.
>>
>>>
>>>
>>>>>
>>>>> The word "region" is used in these parameters, but they don't mean 
>>>>> the same thing.
>>>>>
>>>>> GrowableArray<MemRegion> *regions
>>>>> int first_region, int max_num_regions,
>>>>>
>>>>>
>>>>> How about regions      -> g1_regions_list
>>>>>           first_region -> first_region_in_archive
>>>>
>>>> The GrowableArray above is the MemRegions that GC code gives back 
>>>> to us. The GC code combines multiple G1 regions. The comments 
>>>> probably are over-explaining the details, which are hidden in the 
>>>> GC code. Probably that’s the confusing source. I’ll make the 
>>>> comment more clear.
>>>>
>>>> Using g1_regions_list would also be confusing, since 
>>>> write_archive_heap_regions does not handle G1 regions directly. It 
>>>> processes the MemRegion array that GC code returns. How about 
>>>> changing ‘regions’ to ‘mem_regions’ or ‘archive_regions'?
>>>>
>>> How about heap_regions? These are regions in the active Java heap, 
>>> which current has not mapped anything from the CDS archive.
>>
>> Ok.
>>
>> I’m updating my changes and will send out a consolidated webrev.
>>
>> Thanks!
>> Jiangli
>>
>>>
>>>
>>>>>
>>>>>
>>>>> In the comments, I find the phrase 'the current archive heap 
>>>>> region' ambiguous. It could be (erroneously) interpreted as "a 
>>>>> region from the currently mapped archive”
>>>>>
>>>>> To make it unambiguous, how about changing
>>>>>
>>>>>
>>>>>  464 // Write the current archive heap region, which contains one 
>>>>> or multiple GC(G1) regions.
>>>>>
>>>>>
>>>>> to
>>>>>
>>>>>     // Write the given list of G1 memory regions into the archive, 
>>>>> starting at
>>>>>     // first_region_in_archive.
>>>>
>>>>
>>>> Ok. How about the following:
>>>>
>>>> // Write the given list of java heap memory regions into the 
>>>> archive, starting at
>>>> // first_region_in_archive.
>>>>
>>> Sounds good.
>>>
>>> Thanks
>>> - Ioi
>>>
>>>>>
>>>>>
>>>>> Also, for the explanation of how the G1 regions are written into 
>>>>> the archive, how about:
>>>>>
>>>>>    // The G1 regions in the list are sorted in ascending address 
>>>>> order. When there are more objects
>>>>>    // than the capacity of a single G1 region, the bottom-most G1 
>>>>> region may be partially filled, and the
>>>>>    // remaining G1 region(s) are consecutively allocated and fully 
>>>>> filled.
>>>>>    //
>>>>>    // Thus, the bottom-most G1 region (if not empty) is written 
>>>>> into first_region_in_archive.
>>>>>    // The remaining G1 regions (if exist) are coalesced and 
>>>>> written as a single block
>>>>>    // into (first_region_in_archive + 1)
>>>>>
>>>>>    // Here's the mapping from (g1 regions) -> (archive regions).
>>>>>
>>>>>
>>>>> All this function needs to do is to decide the values for
>>>>>
>>>>>      r0_start, r0_top
>>>>>      r1_start, r1_top
>>>>>
>>>>> I think it would be much better to not use the loop, and not use 
>>>>> the max_num_regions parameter (it's always 2 anyway).
>>>>>
>>>>>      *r0_start = *r0_top = NULL;
>>>>>      *r1_start = *r1_top = NULL;
>>>>>
>>>>>      if (arr_len >= 1) {
>>>>> *r0_start = regions->at(0).start();
>>>>> *r0_end = *r0_start + regions->at(0).byte_size();
>>>>>      }
>>>>>      if (arr_len >= 2) {
>>>>>          int last = arr_len - 1;
>>>>> *r1_start = regions->at(1).start();
>>>>> *r1_end = regions->at(last).start() + regions->at(last).byte_size();
>>>>>       }
>>>>>
>>>>> what do you think?
>>>>
>>>> We need to write out all archive regions including the empty ones. 
>>>> The loop using max_num_regions is the easiest way. I’d like to 
>>>> remove the code that deals with r0_* and r1_ explicitly. Let me try 
>>>> that.
>>>>
>>>>>
>>>>>
>>>>>
>>>>> (3) metaspace.cpp
>>>>>
>>>>> 3350         // Map the archived heap regions after compressed 
>>>>> pointers
>>>>> 3351         // because it relies on compressed class pointers 
>>>>> setting to work
>>>>>
>>>>> do you mean this?
>>>>>
>>>>>     // Archived heap regions depend on the parameters of 
>>>>> compressed class pointers, so
>>>>>     // they must be mapped after such parameters have been decided 
>>>>> in the above call.
>>>>
>>>> Hmmm, maybe use ‘arguments’ instead of ‘parameters’?
>>>>
>>>>>
>>>>>
>>>>> (4) I found this name not strictly grammatical. How about this:
>>>>>
>>>>>      allow_archive_heap_object -> is_heap_object_archiving_allowed
>>>>
>>>> Ok.
>>>>
>>>>>
>>>>> (5) in most of your code, 'archive' is used as a noun, except in 
>>>>> StringTable::archive_string() where it's used as a verb.
>>>>>
>>>>> archive_string could also be interpreted erroneously as "return a 
>>>>> string that's already in the archive". So to be consistent and 
>>>>> unambiguous, I think it's better to rename it to 
>>>>> StringTable::create_archived_string()
>>>>
>>>> Ok.
>>>>
>>>> Thanks,
>>>> Jiangli
>>>>
>>>>>
>>>>>
>>>>> Thanks
>>>>> - Ioi
>>>>>
>>>>>
>>>>> On 8/3/17 5:15 PM, Jiangli Zhou wrote:
>>>>>> Here are the updated webrevs.
>>>>>>
>>>>>> http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.02/ 
>>>>>> <http://cr.openjdk.java.net/%7Ejiangli/8179302/webrev.hotspot.02/>
>>>>>> http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.02/
>>>>>>
>>>>>> Changes in the updated webrevs include:
>>>>>>
>>>>>>   * Merge with Ioi’s recent shared space auto-sizing change (8072061)
>>>>>>   * Addressed all feedbacks from Ioi and Coleen (Thanks for
>>>>>>     detailed review!)
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Jiangli
>>>>>>
>>>>>>
>>>>>>> On Aug 1, 2017, at 5:29 PM, Jiangli Zhou 
>>>>>>> <jiangli.zhou at Oracle.COM> wrote:
>>>>>>>
>>>>>>> Hi Ioi,
>>>>>>>
>>>>>>> Thank you so much for reviewing this. I’ve addressed all your 
>>>>>>> feedbacks. Please see details below. I’ll updated the webrev 
>>>>>>> after addressing Coleen’s comments.
>>>>>>>
>>>>>>>> On Jul 30, 2017, at 9:07 PM, Ioi Lam <ioi.lam at oracle.com> wrote:
>>>>>>>>
>>>>>>>> Hi Jiangli,
>>>>>>>>
>>>>>>>> Here are my comments. I've not reviewed the GC code and I'll 
>>>>>>>> leave that to the GC experts :-)
>>>>>>>>
>>>>>>>> stringTable.cpp: StringTable::archive_string
>>>>>>>>
>>>>>>>>    add assert for DumpSharedSpaces only
>>>>>>>
>>>>>>> Ok.
>>>>>>>
>>>>>>>>
>>>>>>>> filemap.cpp
>>>>>>>>
>>>>>>>> 525 void 
>>>>>>>> FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion> 
>>>>>>>> *regions,
>>>>>>>> 526  int first_region, int num_regions) {
>>>>>>>>
>>>>>>>> When I first read this function, I found it hard to follow, 
>>>>>>>> especially this part that coalesces the trailing regions:
>>>>>>>>
>>>>>>>> 537         int len = regions->length();
>>>>>>>> 538         if (len > 1) {
>>>>>>>> 539           start = (char*)regions->at(1).start();
>>>>>>>> 540           size = (char*)regions->at(len - 1).end() - start;
>>>>>>>> 541         }
>>>>>>>> 542       }
>>>>>>>>
>>>>>>>> The rest of filemap.cpp always perform identical operations on 
>>>>>>>> MemRegion arrays, which are either 1 or 2 in size. However, 
>>>>>>>> this function doesn't follow that pattern; it also has a very 
>>>>>>>> different notion of "region", and the confusing part is 
>>>>>>>> regions->size() is not the same as num_regions.
>>>>>>>>
>>>>>>>> How about we change the API to something like the following? 
>>>>>>>> Before calling this API, the caller needs to coalesce the 
>>>>>>>> trailing G1 regions into a single MemRegion.
>>>>>>>>
>>>>>>>> FileMapInfo::write_archive_heap_regions(MemRegion *regions, int 
>>>>>>>> first, int num_regions) {
>>>>>>>>        if (first == MetaspaceShared::first_string) {
>>>>>>>> assert(num_regons <=  MetaspaceShared::max_strings, "...");
>>>>>>>>        } else {
>>>>>>>>           assert(first == 
>>>>>>>> MetaspaceShared::first_open_archive_heap_region, "...");
>>>>>>>> assert(num_regons <= 
>>>>>>>> MetaspaceShared::max_open_archive_heap_region, "...");
>>>>>>>> }
>>>>>>>>        ....
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> I’ve reworked the function and simplified the code.
>>>>>>>
>>>>>>>>
>>>>>>>> 756   if (!string_data_mapped) {
>>>>>>>> 757 StringTable::ignore_shared_strings(true);
>>>>>>>> 758 assert(string_ranges == NULL && num_string_ranges == 0, 
>>>>>>>> "sanity");
>>>>>>>> 759   }
>>>>>>>> 760
>>>>>>>> 761   if (open_archive_heap_data_mapped) {
>>>>>>>> 762 MetaspaceShared::set_open_archive_heap_region_mapped();
>>>>>>>> 763   } else {
>>>>>>>> 764 assert(open_archive_heap_ranges == NULL && 
>>>>>>>> num_open_archive_heap_ranges == 0, "sanity");
>>>>>>>> 765   }
>>>>>>>>
>>>>>>>> Maybe the two "if" statements should be more consistent? 
>>>>>>>> Instead of StringTable::ignore_shared_strings, how 
>>>>>>>> about StringTable::set_shared_strings_region_mapped()?
>>>>>>>
>>>>>>> Fixed.
>>>>>>>
>>>>>>>>
>>>>>>>> FileMapInfo::map_heap_data() --
>>>>>>>>
>>>>>>>> 818     char* addr = (char*)regions[i].start();
>>>>>>>> 819     char* base = os::map_memory(_fd, _full_path, 
>>>>>>>> si->_file_offset,
>>>>>>>> 820             addr, regions[i].byte_size(), si->_read_only,
>>>>>>>> 821 si->_allow_exec);
>>>>>>>>
>>>>>>>> What happens when the first region succeeds to map but the 
>>>>>>>> second region fails to map? Will both regions be unmapped? I 
>>>>>>>> don't see where you store the return value (base) from 
>>>>>>>> os::map_memory(). Does it mean the code assumes that (addr == 
>>>>>>>> base). If so, we need an assert here.
>>>>>>>
>>>>>>> If any of the region fails to map, we bail out and call 
>>>>>>> dealloc_archive_heap_regions(), which handles the deallocation 
>>>>>>> of any regions specified. If second region fails to map, all 
>>>>>>> memory ranges specified by ‘regions’ array are deallocated. We 
>>>>>>> don’t unmap the memory here since it is part of the java heap. 
>>>>>>> Unmapping of heap memory are handled by GC code. The ‘if’ check 
>>>>>>> below makes sure base == addr.
>>>>>>>
>>>>>>>     if (base == NULL || base != addr) {
>>>>>>>       // dealloc the regions from java heap
>>>>>>> dealloc_archive_heap_regions(regions, region_num);
>>>>>>>   if (log_is_enabled(Info, cds)) {
>>>>>>> log_info(cds)("UseSharedSpaces: Unable to map at required 
>>>>>>> address in java heap.");
>>>>>>>       }
>>>>>>>       return false;
>>>>>>>     }
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> constantPool.cpp
>>>>>>>>
>>>>>>>>     Handle refs_handle;
>>>>>>>>     ...
>>>>>>>>     refs_handle = Handle(THREAD, (oop)archived);
>>>>>>>>
>>>>>>>> This will first create a NULL handle, then construct a 
>>>>>>>> temporary handle, and then assign the temp handle back to the 
>>>>>>>> null handle. This means two handles will be pushed onto 
>>>>>>>> THREAD->metadata_handles()
>>>>>>>>
>>>>>>>> I think it's more efficient if you merge these into a single 
>>>>>>>> statement
>>>>>>>>
>>>>>>>>     Handle refs_handle(THREAD, (oop)archived);
>>>>>>>
>>>>>>> Fixed.
>>>>>>>
>>>>>>>>
>>>>>>>> Is this experimental code? Maybe it should be removed?
>>>>>>>>
>>>>>>>> 664     if (tag_at(index).is_unresolved_klass()) {
>>>>>>>> 665 #if 0
>>>>>>>> 666       CPSlot entry = cp->slot_at(index);
>>>>>>>> 667       Symbol* name = entry.get_symbol();
>>>>>>>> 668       Klass* k = SystemDictionary::find(name, NULL, NULL, 
>>>>>>>> THREAD);
>>>>>>>> 669       if (k != NULL) {
>>>>>>>> 670 klass_at_put(index, k);
>>>>>>>> 671       }
>>>>>>>> 672 #endif
>>>>>>>> 673     } else
>>>>>>>
>>>>>>> Removed.
>>>>>>>
>>>>>>>>
>>>>>>>> cpCache.hpp:
>>>>>>>>
>>>>>>>>     u8 _archived_references
>>>>>>>>
>>>>>>>> shouldn't this be declared as an narrowOop to avoid the type 
>>>>>>>> casts when it's used?
>>>>>>>
>>>>>>> Ok.
>>>>>>>
>>>>>>>>
>>>>>>>> cpCache.cpp:
>>>>>>>>
>>>>>>>>    add assert so that one of these is used only at dump time 
>>>>>>>> and the other only at run time?
>>>>>>>>
>>>>>>>> 610 oop ConstantPoolCache::archived_references() {
>>>>>>>> 611   return 
>>>>>>>> oopDesc::decode_heap_oop((narrowOop)_archived_references);
>>>>>>>> 612 }
>>>>>>>> 613
>>>>>>>> 614 void ConstantPoolCache::set_archived_references(oop o) {
>>>>>>>> 615 _archived_references = (u8)oopDesc::encode_heap_oop(o);
>>>>>>>> 616 }
>>>>>>>
>>>>>>> Ok.
>>>>>>>
>>>>>>> Thanks!
>>>>>>>
>>>>>>> Jiangli
>>>>>>>
>>>>>>>>
>>>>>>>> Thanks!
>>>>>>>> - Ioi
>>>>>>>>
>>>>>>>> On 7/27/17 1:37 PM, Jiangli Zhou wrote:
>>>>>>>>> Sorry, the mail didn’t handle the rich text well. I fixed the 
>>>>>>>>> format below.
>>>>>>>>>
>>>>>>>>> Please help review the changes for JDK-8179302 (Pre-resolve 
>>>>>>>>> constant pool string entries and cache resolved_reference 
>>>>>>>>> arrays in CDS archive). Currently, the CDS archive can contain 
>>>>>>>>> cached class metadata, interned java.lang.String objects. This 
>>>>>>>>> RFE adds the constant pool ‘resolved_references’ arrays 
>>>>>>>>> (hotspot specific) to the archive for startup/runtime 
>>>>>>>>> performance enhancement. The ‘resolved_references' arrays are 
>>>>>>>>> used to hold references of resolved constant pool entries 
>>>>>>>>> including Strings, mirrors, etc. With 
>>>>>>>>> the 'resolved_references’ being cached, string constants in 
>>>>>>>>> shared classes can now be resolved to existing interned 
>>>>>>>>> java.lang.Strings at CDS dump time. G1 and 64-bit platforms 
>>>>>>>>> are required.
>>>>>>>>>
>>>>>>>>> The GC changes in the RFE were discussed and guided by Thomas 
>>>>>>>>> Schatzl and GC team. Part of the changes were contributed by 
>>>>>>>>> Thomas himself.
>>>>>>>>> RFE: https://bugs.openjdk.java.net/browse/JDK-8179302
>>>>>>>>> hotspot: 
>>>>>>>>> http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.01/
>>>>>>>>> whitebox: 
>>>>>>>>> http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.01/
>>>>>>>>>
>>>>>>>>> Please see below for details of supporting cached 
>>>>>>>>> ‘resolved_references’ and pre-resolving string constants.
>>>>>>>>>
>>>>>>>>> Types of Pinned G1 Heap Regions
>>>>>>>>>
>>>>>>>>> The pinned region type is a super type of all archive region 
>>>>>>>>> types, which include the open archive type and the closed 
>>>>>>>>> archive type.
>>>>>>>>>
>>>>>>>>> 00100 0 [ 8] Pinned Mask
>>>>>>>>> 01000 0 [16] Old Mask
>>>>>>>>> 10000 0 [32] Archive Mask
>>>>>>>>> 11100 0 [56] Open Archive:   ArchiveMask | PinnedMask | OldMask
>>>>>>>>> 11100 1 [57] Closed Archive: ArchiveMask | PinnedMask | 
>>>>>>>>> OldMask + 1
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Pinned Regions
>>>>>>>>>
>>>>>>>>> Objects within the region are 'pinned', which means GC does 
>>>>>>>>> not move any live objects. GC scans and marks objects in the 
>>>>>>>>> pinned region as normal, but skips forwarding live objects. 
>>>>>>>>> Pointers in live objects are updated. Dead objects 
>>>>>>>>> (unreachable) can be collected and freed.
>>>>>>>>>
>>>>>>>>> Archive Regions
>>>>>>>>>
>>>>>>>>> The archive types are sub-types of 'pinned'. There are two 
>>>>>>>>> types of archive region currently, open archive and closed 
>>>>>>>>> archive. Both can support caching java heap objects via the 
>>>>>>>>> CDS archive.
>>>>>>>>>
>>>>>>>>> An archive region is also an old region by design.
>>>>>>>>>
>>>>>>>>> Open Archive (GC-RW) Regions
>>>>>>>>>
>>>>>>>>> Open archive region is GC writable. GC scans & marks objects 
>>>>>>>>> within the region and adjusts (updates) pointers in live 
>>>>>>>>> objects the same way as a pinned region. Live objects 
>>>>>>>>> (reachable) are pinned and not forwarded by GC.
>>>>>>>>> Open archive region does not have 'dead' objects. Unreachable 
>>>>>>>>> objects are 'dormant' objects. Dormant objects are not 
>>>>>>>>> collected and freed by GC.
>>>>>>>>>
>>>>>>>>> Adjustable Outgoing Pointers
>>>>>>>>>
>>>>>>>>> As GC can adjust pointers within the live objects in open 
>>>>>>>>> archive heap region, objects can have outgoing pointers to 
>>>>>>>>> another java heap region, including closed archive region, 
>>>>>>>>> open archive region, pinned (or humongous) region, and normal 
>>>>>>>>> generational region. When a referenced object is moved by GC, 
>>>>>>>>> the pointer within the open archive region is updated accordingly.
>>>>>>>>>
>>>>>>>>> Closed Archive (GC-RO) Regions
>>>>>>>>>
>>>>>>>>> The closed archive region is GC read-only region. GC cannot 
>>>>>>>>> write into the region. Objects are not scanned and marked by 
>>>>>>>>> GC. Objects are pinned and not forwarded. Pointers are not 
>>>>>>>>> updated by GC either. Hence, objects within the archive region 
>>>>>>>>> cannot have any outgoing pointers to another java heap region. 
>>>>>>>>> Objects however can still have pointers to other objects 
>>>>>>>>> within the closed archive regions (we might allow pointers to 
>>>>>>>>> open archive regions in the future). That restricts the type 
>>>>>>>>> of java objects that can be supported by the archive region.
>>>>>>>>> In JDK 9 we support archive Strings with the archive regions.
>>>>>>>>>
>>>>>>>>> The GC-readonly archive region makes java heap memory sharable 
>>>>>>>>> among different JVM processes. NOTE: synchronization on the 
>>>>>>>>> objects within the archive heap region can still cause writes 
>>>>>>>>> to the memory page.
>>>>>>>>>
>>>>>>>>> Dormant Objects
>>>>>>>>>
>>>>>>>>> Dormant objects are unreachable java objects within the open 
>>>>>>>>> archive heap region.
>>>>>>>>> A java object in the open archive heap region is a live object 
>>>>>>>>> if it can be reached during scanning. Some of the java objects 
>>>>>>>>> in the region may not be reachable during scanning. Those 
>>>>>>>>> objects are considered as dormant, but not dead. For example, 
>>>>>>>>> a constant pool 'resolved_references' array is reachable via 
>>>>>>>>> the klass root if its container klass (shared) is already 
>>>>>>>>> loaded at the time during GC scanning. If a shared klass is 
>>>>>>>>> not yet loaded, the klass root is not scanned and it's 
>>>>>>>>> constant pool 'resolved_reference' array (A) in the open 
>>>>>>>>> archive region is not reachable. Then A is a dormant object.
>>>>>>>>>
>>>>>>>>> Object State Transition
>>>>>>>>>
>>>>>>>>> All java objects are initially dormant objects when open 
>>>>>>>>> archive heap regions are mapped to the runtime java heap. A 
>>>>>>>>> dormant object becomes live object when the associated shared 
>>>>>>>>> class is loaded at runtime. Explicit call 
>>>>>>>>> to G1SATBCardTableModRefBS::enqueue() needs to be made when a 
>>>>>>>>> dormant object becomes live. That should be the case 
>>>>>>>>> for cached objects with strong roots as well, since strong 
>>>>>>>>> roots are only scanned at the start of GC marking (the initial 
>>>>>>>>> marking) but not during Remarking/Final marking. If a cached 
>>>>>>>>> object becomes live during concurrent marking phase, G1 may 
>>>>>>>>> not find it and mark it live unless a call to 
>>>>>>>>> G1SATBCardTableModRefBS::enqueue() is made for the object.
>>>>>>>>>
>>>>>>>>> Currently, a live object in the open archive heap region 
>>>>>>>>> cannot become dormant again. This restriction simplifies GC 
>>>>>>>>> requirement and guarantees all outgoing pointers are updated 
>>>>>>>>> by GC correctly. Only objects for shared classes from the 
>>>>>>>>> builtin class loaders (boot, PlatformClassLoaders, and 
>>>>>>>>> AppClassLoaders) are supported for caching.
>>>>>>>>>
>>>>>>>>> Caching Java Objects at Archive Dump Time
>>>>>>>>>
>>>>>>>>> The closed archive and open archive regions are allocated near 
>>>>>>>>> the top of the dump time java heap. Archived java objects 
>>>>>>>>> are copied into the designated archive heap regions. For 
>>>>>>>>> example, String objects and the underlying 'value' arrays are 
>>>>>>>>> copied into the closed archive regions. All references to the 
>>>>>>>>> archived objects (from shared class metadata, string table, 
>>>>>>>>> etc) are set to the new heap locations. A hash table is used 
>>>>>>>>> to keep track of all archived java objects during the copying 
>>>>>>>>> process to make sure java object is not archived more than 
>>>>>>>>> once if reached from different roots. It also makes sure 
>>>>>>>>> references to the same archived object are updated using the 
>>>>>>>>> same new address location.
>>>>>>>>>
>>>>>>>>> Caching Constant Pool resolved_references Array
>>>>>>>>>
>>>>>>>>> The 'resolved_references' is an array that holds references of 
>>>>>>>>> resolved constant pool entries including Strings, mirrors 
>>>>>>>>> and methodTypes, etc. Each loaded class has one 
>>>>>>>>> 'resolved_references' array (in ConstantPoolCache). The 
>>>>>>>>> 'resolved_references' arrays are copied into the open archive 
>>>>>>>>> regions during dump process. Prior to copying the 
>>>>>>>>> 'resolved_references' arrays, JVM iterates through constant 
>>>>>>>>> pool entries and resolves all JVM_CONSTANT_String entries to 
>>>>>>>>> existing interned Strings for all archived classes. When 
>>>>>>>>> resolving, JVM only looks up the string table and finds 
>>>>>>>>> existing interned Strings without inserting new ones. If 
>>>>>>>>> a string entry cannot be resolved to an existing interned 
>>>>>>>>> String, the constant pool entry remain as unresolved. That 
>>>>>>>>> prevents memory waste if a constant pool string entry is never 
>>>>>>>>> used at runtime.
>>>>>>>>>
>>>>>>>>> All String objects referenced by the string table are copied 
>>>>>>>>> first into the closed archive regions. The string table entry 
>>>>>>>>> is updated with the new location when each String object is 
>>>>>>>>> archived. The JVM updates the resolved constant pool string 
>>>>>>>>> entries with the new object locations when copying the 
>>>>>>>>> 'resolved_references' arrays to the open archive regions. 
>>>>>>>>> References to the 'resolved_references' arrays in the 
>>>>>>>>> ConstantPoolCache are also updated.
>>>>>>>>> At runtime as part of ConstantPool::restore_unshareable_info() 
>>>>>>>>> work, call G1SATBCardTableModRefBS::enqueue() to let GC 
>>>>>>>>> know the 'resolved_references' is becoming live. A handle is 
>>>>>>>>> created for the cached object and added to the loader_data's 
>>>>>>>>> handles.
>>>>>>>>>
>>>>>>>>> Runtime Java Heap With Cached Java Objects
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The closed archive regions (the string regions) and open 
>>>>>>>>> archive regions are mapped to the runtime java heap at the 
>>>>>>>>> same offsets as the dump time offsets from the runtime java 
>>>>>>>>> heap base.
>>>>>>>>>
>>>>>>>>> Preliminary test execution and status:
>>>>>>>>>
>>>>>>>>> JPRT: passed
>>>>>>>>> Tier2-rt: passed
>>>>>>>>> Tier2-gc: passed
>>>>>>>>> Tier2-comp: passed
>>>>>>>>> Tier3-rt: passed
>>>>>>>>> Tier3-gc: passed
>>>>>>>>> Tier3-comp: passed
>>>>>>>>> Tier4-rt: passed
>>>>>>>>> Tier4-gc: passed
>>>>>>>>> Tier4-comp:6 jobs timed out, all other tests passed
>>>>>>>>> Tier5-rt: one test failed but passed when running locally, all 
>>>>>>>>> other tests passed
>>>>>>>>> Tier5-gc: passed
>>>>>>>>> Tier5-comp: running
>>>>>>>>> hotspot_gc: two jobs timed out, all other tests passed
>>>>>>>>> hotspot_gc in CDS mode: two jobs timed out, all other tests passed
>>>>>>>>> vm.gc: passed
>>>>>>>>> vm.gc in CDS mode: passed
>>>>>>>>> Kichensink: passed
>>>>>>>>> Kichensink in CDS mode: passed
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Jiangli
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/hotspot-gc-dev/attachments/20170810/272a5c90/attachment.htm>


More information about the hotspot-gc-dev mailing list