Question about JEP 371 and unloading Lambdas
thomas.stuefe at gmail.com
Wed Jun 10 06:19:43 UTC 2020
On Tue, Jun 9, 2020 at 8:50 PM Mandy Chung <mandy.chung at oracle.com> wrote:
> Hi Thomas,
> On 6/9/20 1:46 AM, Thomas Stüfe wrote:
> I currently try to understand how metaspace usage of Lambda proxies is
> affected with JEP 371. Could you please confirm if my understanding is
> Lambdas live as long as the lookup class lives, which would be the class
> containing the lambda expression.
> Yes the current implementation  defines the lambda proxy class as a
> hidden class with strong link to its defining loader.
> As for storage of metadata, in older JDKs Lambdas used anonymous classes,
> which meant each lambda class had its own associated CLD. Since JEP 371
> (?), the lambda class seems now directly associated with the CLD of the
> loader of the lookup class.
> So, metaspace storage is more efficient since
> we reuse the existing metaspace arena of the loader.
> AFAICT less potential metaspace storage fragmentation.
> I guess this makes
> sense if the lifetime of the lambda is bound to that of the lookup class
> anyway, since that won't be unloaded until its loader goes away (or, if it
> itself is a hidden class, its CLD).
> Have I got this right?
> You got this right.
Thank you for the confirmation.
> I love to get your confirmation if you have also observed the metaspace
> storage more efficient after JEP 371 integration.
As far as Lambdas are concerned, definitely. A test with 20000 Lambdas
Non-class space: 66,00 MB reserved, 64,75 MB ( 98%) committed
Class space: 1,00 GB reserved, 21,32 MB ( 2%) committed
Both: 1,06 GB reserved, 86,07 MB ( 8%) committed
Waste (percentages refer to total committed size 86,07 MB):
Committed unused: 201,00 KB ( <1%)
Waste in chunks in use: 3,57 KB ( <1%)
Free in chunks in use: 13,78 MB ( 16%)
Overhead in chunks in use: 3,74 MB ( 4%)
In free chunks: 0 bytes ( 0%)
Deallocated from chunks in use: 1,25 MB ( 1%) (20537 blocks)
-total-: 18,97 MB ( 22%)
Non-class space: 58,00 MB reserved, 56,21 MB ( 97%) committed
Class space: 1,00 GB reserved, 13,00 MB ( 1%) committed
Both: 1,06 GB reserved, 69,21 MB ( 6%) committed
Waste (percentages refer to total committed size 69,21 MB):
Committed unused: 176,00 KB ( <1%)
Waste in chunks in use: 4,27 KB ( <1%)
Free in chunks in use: 1,09 MB ( 2%)
Overhead in chunks in use: 84,38 KB ( <1%)
In free chunks: 1,15 MB ( 2%)
Deallocated from chunks in use: 208,97 KB ( <1%) (766 blocks)
-total-: 2,70 MB ( 4%)
A reduction in waste from 22% to 4%, mainly due to reduced leftover space
in half-eaten chunks. Usage drops from 86M->69M.
But the saved memory is only part of the story. We save a lot of overhead
too, e.g. less CLDs so smaller CLDG. Also we save storage for the CLDs.
Also less time spent inside Metaspace critical sections.
This is a good thing :) Swarms of anonymous classes have always been an
annoyance for Metaspace since as an arena based allocator 1-class-loaders
are not exactly its strong side. This has never been a really pressing
problem for me since the total waste was usually lowish. But it is nice to
see this gone anyway.
I have two followup questions:
- I do not understand how exactly this relates to Hidden Classes. Could we
have had this improvement before, by allocating metaspace for anonymous
classes for lambda proxies via the CLD of the target class? I ask this
because I want to understand if we can bring this improvement into older
releases, independent from Hidden Classes.
- When I was looking at Lambdas, I really was looking for an example case
with many Hidden Classes whose life time should be quasi random and not
bound to a single class loader. What you describe in the JEP text under
unloading. I wanted to look at what this does with Metaspace. But Lambdas
are a bad example for that, since their lifetimes are still synchronized
with that of the target class. Is there another example or test case for
short-lived Hidden Classes?
> Thank you!
More information about the hotspot-runtime-dev