PRT memory usage
Thomas Schatzl
thomas.schatzl at oracle.com
Mon Aug 21 16:42:18 UTC 2017
Hi,
On Sun, 2017-08-20 at 08:57 +0000, Milan Mimica wrote:
> Hello
>
> I'm (still) trying to figure our high memory usage by PRT. I have
> studied heapRegionRemSet.cpp code and came up with a calculation I
> need you to confirm. Given region size of 8M and default G1 settings:
> * max number of PRT instances is 2^12 for each HR
Where did you get the 2^12 from?
> * PRT size is 64MB
Not completely following, where from do you understand that max prt
size is 64MB?
8M region size implies a 2k PRT (bitmap) size (one bit per 512 bytes)
>
> I'm looking at the worst-case scenario and I don't dare to multiply
> the tree numbers. The cap is just to high. Am I missing something?
> Do only Young HR get a OtherRegionsTable?
All regions get them. But there are no PRTs from young regions to old
regions. Humongous continues regions don't have any remembered set.
> Where can I find the number of regions per generation? I cannot spot
> it in GC logs.
-Xlog:gc+heap=info gives you the following kind of output:
[15.369s][info ][gc,heap ] GC(0) Eden regions: 3->0(576)
[15.369s][info ][gc,heap ] GC(0) Survivor regions: 0->0(0)
[15.369s][info ][gc,heap ] GC(0) Old regions: 0->1
[15.369s][info ][gc,heap ] GC(0) Humongous regions: 0->0
Here is some rough calculation for remembered set size for jdk8
(copy&pasted from some other email from some time ago - I did not check
it again, so there might be some omissions):
"[...]
for every region in #non-young-regions:
e1) coarse table: one bit for every #regions +
MAX(
e2) sparse table: (2 * #regions) * (8 + #sparse-entries * 4)
e3) fine table: MIN(#fine-entries, #non-young-regions - 1) * (bit
per #cards-per-region + 8 + 56)
)
where:
#regions = maximum number of regions in heap = -Xmx / G1HeapRegionSize
#cards-per-region = G1HeapRegionSize / 512
#non-young-regions = #regions - #minimum-number-of-young-regions
#minimum-number-of-regions = #regions * G1NewSizePercent / 100
#sparse-entries = G1RSetSparseRegionEntries
#fine-entries = MIN(G1RSetRegionEntries, #non-young-regions)
Default values of options:
G1NewSizePercent = 5
G1RSetSparseRegionEntries = G1RSetSparseRegionEntriesBase *
(log2(#G1HeapRegionSize-in-MB) + 1)
G1RSetSparseRegionEntriesBase = 4
This is I think a reasonably accurate worst case memory usage.
[...]
The remembered set holds the greatest potential (but also the largest
risk to introduce performance issues) for savings.
This is due to the fact that actually every entry in a remembered set
(there, every region A stores for every other region x_0, ..., x_n the
cards that contain references to A) can either take memory in e1, e2,
or e3 (actually only the latter two for simplicity).
I.e. G1 can represent such an x_i in one of the data structures of e1,
e2, and e3, with different memory/performance characteristics.
The direction of representation is e2, then e3 and finally e1
(unfortunately there is no way to go back; when a region is freed, its
remembered set goes back to e2).
So what could be tried is trying to keep x_i at e2 level - that can be
controlled by G1RSetSparseRegionEntries. A given value of
G1RSetSparseRegionEntries indicates how many cards it can store - if
that is not enough, it expands to e3. (Just for reference:
G1RSetRegionEntries determines how many of e3 a remembered set for a
region A can hold - if more, it selects one to evict to e1; this is the
dreaded "coarsening" if you ever heard of it. Setting
G1RSetRegionEntries to something >= the number of regions avoids that
coarsening)
Since e2 is slightly more memory efficient, it might be worth trying to
bump G1RSetSparseRegionEntries.
If you think all what I explained above is gibberish to you, and
you are still interested, I can try to explain it a bit better :)
JDK9 made e2 more memory-efficient (only takes 1/4th of memory as
before), and does not create e1 if not needed.
[...]"
Hth,
Thomas
More information about the hotspot-gc-use
mailing list