The JEP covers the idea very well, so I'm only covering some implementation 
details here:

* regions get a "pin count" (reference count). As long as it is non-zero, we 
conservatively never reclaim that region even if there is no reference in 
there. JNI code might have references to it.

* the JNI spec only requires us to provide pinning support for typeArrays, 
nothing else. This implementation uses this in various ways:

  * when evacuating from a pinned region, we evacuate everything live but the 
typeArrays to get more empty regions to clean up later.

  * when formatting dead space within pinned regions we use filler objects. 
Pinned regions may be referenced by JNI code only, so we can't overwrite 
contents of any dead typeArray either. These dead but referenced typeArrays 
luckily have the same header size of our filler objects, so we can use their 
headers for our fillers. The problem is that previously there has been that 
restriction that filler objects are half a region size at most, so we can end 
up with the need for placing a filler object header inside a typeArray. The 
code could be clever and handle this situation by splitting the to be filled 
area so that this can't happen, but the solution taken here is allowing filler 
arrays to cover a whole region. They are not referenced by Java code anyway, so 
there is no harm in doing so (i.e. gc code never touches them anyway).

* G1 currently only ever actually evacuates young pinned regions. Old pinned 
regions of any kind are never put into the collection set and automatically 
skipped. However assuming that the pinning is of short length, we put them into 
the candidates when we can.

  * there is the problem that if an applications pins a region for a long time 
g1 will skip evacuating that region over and over. that may lead to issues with 
the current policy in marking regions (only exit mixed phase when there are no 
marking candidates) and just waste of processing time (when the candidate stays 
in the retained candidates)

    The cop-out chosen here is to "age out" the regions from the candidates and 
wait until the next marking happens.

    I.e. pinned marking candidates are immediately moved to retained 
candidates, and if in total the region has been pinned for 
`G1NumCollectionsKeepUnreclaimable` collections it is dropped from the 
candidates. Its current value is fairly random.

* G1 pauses got a new tag if there were pinned regions in the collection set. 
I.e. in addition to something like:

  `GC(6) Pause Young (Normal) (Evacuation Failure) 1M->1M(22M) 36.16ms`

  there is that new tag `(Pinned)` that indicates that one or more regions that 
were pinned
  were encountered during gc. E.g.

  `GC(6) Pause Young (Normal) (Pinned) (Evacuation Failure) 1M->1M(22M) 36.16ms`

  `Pinned` and `Evacuation Failure` tags are not exclusive. GC might have 
encountered both pinned
  regions and evacuation failed regions in the same collection or even in the 
same region. (I am
  open to a better name for the `(Pinned)` tag)

Testing: tier1-8

-------------

Commit messages:
 - Improve somewhat unstable test
 - Fix typo in 
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java so 
that resourcehogs/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java does 
not fail
 - Fix minimal build
 - Region pinning in G1/JEP-423

Changes: https://git.openjdk.org/jdk/pull/16342/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=16342&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8318706
  Stats: 1547 lines in 54 files changed: 922 ins; 422 del; 203 mod
  Patch: https://git.openjdk.org/jdk/pull/16342.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/16342/head:pull/16342

PR: https://git.openjdk.org/jdk/pull/16342

Reply via email to