Improving AppCDS for Custom Loaders

Jiangli Zhou jiangli.zhou at oracle.com
Thu May 3 17:34:02 UTC 2018


> On May 3, 2018, at 2:14 AM, Volker Simonis <volker.simonis at gmail.com> wrote:
> 
> On Thu, May 3, 2018 at 11:01 AM, David Holmes <david.holmes at oracle.com> wrote:
>> On 3/05/2018 5:16 PM, Volker Simonis wrote:
>>> 
>>> On Thu, May 3, 2018 at 8:55 AM, David Holmes <david.holmes at oracle.com>
>>> wrote:
>>>> 
>>>> Just lurking here but ...
>>>> 
>>>>> But is this really y relevant use case? Why would I like to create ONE
>>>>> archive for several apps? This would actually increase the footprint
>>>>> of a single instance which uses this archive. If I have several apps I
>>>>> would expect that users create a specific archive for each app to get
>>>>> the best out of CDS.
>>>> 
>>>> 
>>>> 
>>>> One app instance may get increased footprint but you presumably use CDS
>>>> because you have multiple apps running (whether the same or not). These
>>>> apps
>>>> all share the core JDK classes from the archive so the overall footprint
>>>> per
>>>> instance is less.
>>>> 
>>> 
>>> If we just want to share the core JDK classes that's easy. For that we
>>> could mostly use the default class list (or a slightly extended one)
>>> which is generated at JDK build time (at JAVA_HOME/lib/classlist).
>> 
>> 
>> The point is that you are presumably running multiple instances of multiple
>> apps, hence you want to share one set of core classes across all, and share
>> the app classes across each app instance.
>> 
> 
> But that would require two archives: a general one with the core
> classes and an application specific one for each application.
> Combining the core classes and the application of various applications
> will not be optimal because the application classes will be all mixed
> in the same archive. The archive is being mapped page-wise into the
> java process so you'll probably end up mapping the whole archive into
> each process although you'll only use a fraction of the classes in the
> archive.
> 
>>> If we want to use ONE archive for several applications and we can
>>> accept to have a bigger footprint if running a single (or just a few)
>>> applications in parallel I suppose the overhead of simply dumping all
>>> the classes from the classpathes of the various applications compared
>>> to an accurate solution where we only dump the actually used classes
>>> of all applications would be not that big.
>> 
>> 
>> But those "accurate" solutions duplicate the core classes and that's a waste
>> of footprint.
>> 
> 
> By "accurate" I meant one "fat" archive which contains all the classes
> USED by several applications plus the core classes. My argument was
> that such an "accurate" "fat" archive won't be much smaller compared
> to a "fat" archive which simply contains all the core classes plus all
> the application classes (i.e. from the application class pathes, no
> matter if they are ever used or not). But the latter would be much
> simpler to implement.

The above discussion and an internal proposal for hybrid archiving seem to converge on a few points. If there is no objection to the hybrid archiving proposal internally, maybe we can shared the details of the proposal on openjdk soon.

Thanks,

Jiangli


> 
>> David
>> -----
>> 
>> 
>>>> David
>>>> -----
>>>> 
>>>> 
>>>> On 3/05/2018 4:48 PM, Volker Simonis wrote:
>>>>> 
>>>>> 
>>>>> On Thu, May 3, 2018 at 6:52 AM, Ioi Lam <ioi.lam at oracle.com> wrote:
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> On 5/2/18 10:00 AM, Volker Simonis wrote:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> On Tue, May 1, 2018 at 8:32 PM, Ioi Lam <ioi.lam at oracle.com> wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> PROBLEM:
>>>>>>>> 
>>>>>>>> As discussed with Volker and Yumin in previous e-mails, AppCDS has
>>>>>>>> some
>>>>>>>> experimental support for custom class loaders. However, it's not very
>>>>>>>> easy
>>>>>>>> to use.
>>>>>>>> 
>>>>>>>> For example, you can write a classlist like this:
>>>>>>>> 
>>>>>>>>       java/lang/Object id: 1
>>>>>>>>       CustomLoadee id: 2 super: 1 source: /tmp/foo.jar
>>>>>>>> 
>>>>>>>> The CustomLoadee class will be stored in the shared archive with a
>>>>>>>> CRC
>>>>>>>> code.
>>>>>>>> During runtime, if a customed loader wants to load a class of the
>>>>>>>> same
>>>>>>>> name,
>>>>>>>> and its classfile has the same size and CRC as the archived class,
>>>>>>>> the
>>>>>>>> archived version will be loaded. This speeds up class loading by
>>>>>>>> avoiding
>>>>>>>> parsing the class file, and saves space by sharing the mmap'ed class
>>>>>>>> metadata across processes.
>>>>>>>> 
>>>>>>>> You can see an example test at:
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> http://hg.openjdk.java.net/jdk/hs/file/46dc568d6804/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java
>>>>>>>> 
>>>>>>>> However, the current scheme requires you to specify all the super
>>>>>>>> classes
>>>>>>>> and interfaces. There's no support provided by the
>>>>>>>> -XX:DumpLoadedClassList
>>>>>>>> option. It can be helped somewhat with Volker's tool:
>>>>>>>> https://github.com/simonis/cl4cds
>>>>>>>> 
>>>>>>>> 
>>>>>>>> POSSIBLE SOLUTIONS:
>>>>>>>> 
>>>>>>>> 1. "Dump-as-you-go". As suggested by Yumin, we can provide a jcmd to
>>>>>>>> ask
>>>>>>>> a
>>>>>>>> running JVM process to dump all of its loaded classes, including
>>>>>>>> those
>>>>>>>> loaded by custom loaders, into an archive. An alternative is to dump
>>>>>>>> the
>>>>>>>> archive at JVM exit time (or when you press Ctrl-C, etc.
>>>>>>>> 
>>>>>>>> 2. Add information about the custom classes for
>>>>>>>> -XX:DumpLoadedClassList.
>>>>>>>> The
>>>>>>>> trouble is some class loaders don't specify a code source that can be
>>>>>>>> understood by the built-in class loaders. For example, the "Fat Jars"
>>>>>>>> would
>>>>>>>> have a code source like
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> jar:file:/jdk/tmp/test-1.0-SNAPSHOT.jar!/BOOT-INF/lib/validation-api-2.0.1.Final.jar!/
>>>>>>>> 
>>>>>>>> also, many custom loaders would pre-process the classfile data before
>>>>>>>> defining the class, so we can't simply archive the version of the
>>>>>>>> class
>>>>>>>> on
>>>>>>>> disk.
>>>>>>>> 
>>>>>>>> One possible solution for #2 is to include the class file data in the
>>>>>>>> -XX:DumpLoadedClassList output:
>>>>>>>> 
>>>>>>>> 
>>>>>>>>       java/lang/Object id: 1
>>>>>>>>       CustomLoadee id: 2 super: 1 source: base64
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> yv66vgAAADQAFwoABAAQCQAFABEHABIHABMHABQBAAJIaQEADElubmVyQ2xhc3NlcwEABjxpbml0
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAFmAQADKClJAQAKU291cmNlRmlsZQEA
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> CkhlbGxvLmphdmEMAAgACQwAFQAWAQAFSGVsbG8BABBqYXZhL2xhbmcvT2JqZWN0AQAISGVsbG8k
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> SGkBAAFYAQABSQAhAAMABAAAAAAAAgABAAgACQABAAoAAAAdAAEAAQAAAAUqtwABsQAAAAEACwAA
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> AAYAAQAAAC8ACAAMAA0AAQAKAAAAHAABAAAAAAAEsgACrAAAAAEACwAAAAYAAQAAADEAAgAOAAAA
>>>>>>>>       AgAPAAcAAAAKAAEABQADAAYACA==
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Of the 2 solutions:
>>>>>>>> 
>>>>>>>> #1 seems easier to use, but may require more invasive modifications
>>>>>>>> in
>>>>>>>> the
>>>>>>>> VM, especially if you want to be able to continue execution after
>>>>>>>> dumping.
>>>>>>>> 
>>>>>>> Not sure what #1 really proposes: dumping the complete .jsa archive at
>>>>>>> runtime or dumping just the loaded classes.
>>>>>>> 
>>>>>>> If it's just about dumping the loaded class without generating the
>>>>>>> .jsa archive there's the problem that by default the VM doesn't store
>>>>>>> the exact bytes of a class after the class was loaded (except when
>>>>>>> class transformers are registered). So the class files would have to
>>>>>>> be re-assembled from the internal VM structures (in the same way this
>>>>>>> is done for class redefinition) and the resulting class-file may be
>>>>>>> different from the original bytes (i.e. some attributes may be
>>>>>>> missing).
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> #1 is for creating the JSA file, not just dumping the class files.
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> If #1 is about creating the whole .jsa archive at runtime (or at VM
>>>>>>> exit) I think that would be the most attractive solution from a
>>>>>>> usability point of view although I understand that #2 will be easier
>>>>>>> to implement in the short term. Regarding the argument that #1 will
>>>>>>> produce a "binary blob" that's true, but that's already true now when
>>>>>>> we use "Xshare:dump". I think it should be not to hard to implement a
>>>>>>> tool based an SA which could introspect a .jsa archive.
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> The argument about the binary blob is to compare it against the text
>>>>>> file
>>>>>> produced by -XX:DumpLoadedClassList.
>>>>>> 
>>>>>> One use case to consider is when you have a JAR file that contains
>>>>>> several
>>>>>> apps that each load a unique set of classes. Today, (assuming that
>>>>>> custom
>>>>>> class loaders are not used), you can run each app once with
>>>>>> -XX:DumpLoadedClassList, and then do an
>>>>>> 
>>>>>>      cat *.classlist | sort | uniq > combined.classlist
>>>>>> 
>>>>>> and then create an archive that would work for all these apps.
>>>>>> 
>>>>> 
>>>>> But is this really y relevant use case? Why would I like to create ONE
>>>>> archive for several apps? This would actually increase the footprint
>>>>> of a single instance which uses this archive. If I have several apps I
>>>>> would expect that users create a specific archive for each app to get
>>>>> the best out of CDS.
>>>>> 
>>>>>> With the binary blob, there's no easy way of doing this. It will be
>>>>>> very
>>>>>> difficult to write a tool to decipher each blob and then somehow
>>>>>> combine
>>>>>> them into a single one.
>>>>>> 
>>>>> 
>>>>> But if users really wants such a "fat" archive, there's a much easier
>>>>> way: just dump ALL the classes from the .jar file into the archive. A
>>>>> class list for this could easily be assembled either with an external
>>>>> tool like cl4cds (or even a simple shell scripts which converts the
>>>>> output of `unzip -l <jar-file>` into the correct format). Or, even
>>>>> simpler, by adding a new option to the VM similar to
>>>>> -XX:DumpLoadedClassList which dumps all the classes it can find on the
>>>>> class path (and potentially other, configurable locations).
>>>>> 
>>>>>> Thanks
>>>>>> - Ioi
>>>>>> 
>>>>>> 
>>>>>>>> #2 would be easier to implement, but the classlist might be huge.
>>>>>>>> 
>>>>>>>> Also, #2 would allow post-processing tools to remove unneeded
>>>>>>>> classes,
>>>>>>>> or
>>>>>>>> merge two runs into a single list. The output of #1 is essentially a
>>>>>>>> binary
>>>>>>>> blob that's impossible for off-line analysis/optimizations.
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Any comments, or suggestions for alternatives?
>>>>>>>> 
>>>>>>>> Thanks
>>>>>>>> - Ioi
>>>>>>>> 
>>>>>>>> 
>>>>>> 
>>>> 
>> 



More information about the hotspot-runtime-dev mailing list