RFR: JDK-8222373 Improve CDS performance for custom class loaders
Ioi Lam
ioi.lam at oracle.com
Thu Jun 20 07:12:03 UTC 2019
On 6/19/19 11:36 PM, Alan Bateman wrote:
> On 20/06/2019 02:36, yumin qi wrote:
>> Hi, Please review:
>> bug: https://bugs.openjdk.java.net/browse/JDK-8222373
>> webrev: http://cr.openjdk.java.net/~minqi/8222373/01/
>>
>> To load shared class from CDS, first class file stream is read from jar
>> file, then load the class with the stream. In vm, the stream is used to
>> calculate file size and crc32 which are used to compare with the counter
>> parts stored in CDS.
>>
>> In fact, when CDS mapped, every SharedClassPathEntry is checked for
>> validation, if there is mismatch JVM will exit. That is, if user updated
>> jars and did not recreated CDS archive, it would fail. This can make us
>> load the class from CDS directly (if it is in CDS) without checking
>> class
>> file length and crc32, so skip getting byte stream from source to
>> save time.
>>
> cc'ing core-libs-dev as this proposal involves changes to the
> ClassLoader API that will require significant discussion. One initial
> concern is that it exposes the notion of "shared class" in the
> standard API. I'm also concerned about the reliance on the protection
> domain and changing existing defineClass methods to allow the class
> bytes be null. How does that work when CDS is disabled - are you
> expecting class loader implementation with go-faster stripes to retry
> a different defineClass with the class bytes? Ioi has had a number of
> proposals in this area (and I see he's added a comment to the bug) but
> we didn't converge on the right API so maybe it time to have another
> attempt at that issue first.
>
> -Alan
I have a rough idea -- let's have a higher-level representation of the
bytecode stream than byte[] or ByteBuffer, to make optimization possible.
So we could have a new API in ClassLoader
protected final Class<?> defineClass(String name, String location,
ProtectionDomain protectionDomain)
and its behavior is equivalent to the following
{
byte[] b = read_buffer_from(location);
return defineClass(name, b, 0, b.len, protectionDomain);
}
examples would be:
defineClass("java/lang/Object",
"jrt:/java.base/java/lang/Object.class", NULL);
defineClass("com/foo/Bar",
"file://path/com.foo.jar!com/foo/Bar.class", myProtectionDomain);
Note that the type and value of <location> is just for illustrative
purposes. We might use a different type (URI??). It's just a way to name
a location that you can read a byte buffer from.
The protectionDomain will need to be created by the caller. The use of
the protectionDomain will be no different than the existing
defineClass() APIs. Specifically, it will not be used in any way to
fetch the buffer.
When CDS is enabled, the VM can check if the name+location matches a
class in the CDS archive. If so, the class is loaded without fetching
the buffer.
The caller doesn't need to know if CDS is enabled or not.
(We probably don't want a String type but a more abstract type. That way
we can evolve it to allow more complex representations, such as "read
the bytecode stream from here, but replace the method name "Foo" to
"Bar", and add a new integer field "X" ....
If John Rose was to design this, I am sure he will call it something
like BytecodeStreamDynamic :-)
This may actually reduce the use of ASM. E.g., today people are forced
to write their own bytecodes, even if they just want some simple
transformation on template classes).
Thanks
- Ioi
More information about the core-libs-dev
mailing list