<div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Dec 16, 2024 at 4:21 AM Alan Bateman <<a href="mailto:alan.bateman@oracle.com" target="_blank">alan.bateman@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
  <div>
    On 14/12/2024 17:10, David Lloyd wrote:<br>
    <blockquote type="cite">
      
      <div dir="ltr">
        <div dir="ltr">
          <div style="font-family:arial,helvetica,sans-serif">:<br>
          </div>
        </div>
        <div class="gmail_quote">
          <div><br>
          </div>
          <div>
            <div style="font-family:arial,helvetica,sans-serif">The reason
              to lazily load and link modules is basically analogous to
              the reason that we lazily load and link classes. In fact
              there is very little difference. While requiring all
              classes to be preloaded may have some benefits in certain
              circumstances (take GraalVM for example), it also
              significantly restricts flexibility in a few important
              ways, and of course has a heavy performance cost, and so
              is not generally considered to be a good strategy for
              application runtimes or even the Java launcher itself.</div>
            <div style="font-family:arial,helvetica,sans-serif"><br>
            </div>
            <div style="font-family:arial,helvetica,sans-serif">For
              modules, we face the same issue. I can, for example,
              create a single application layer with a thousand modules
              in it. Before the application can start, every JAR has to
              be opened and every module has to be loaded, which entails
              parsing or dynamically creating descriptors (generally a
              combination of these things), each with dozens of support
              objects for things like dependencies, exports, and
              services, and then their internal graphs have to be
              resolved and wired and checked for consistency. So there
              is a significant performance cost there.</div>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    Startup with a large number of modules on the application module
    path is an interesting topic. Reliable configuration means the
    modules required by the initial module must be recursively
    enumerated to create the module graph, and this does mean the module
    path must be scanned (once) to find the modules.<br>
    <br>
    Efforts to date have been focused on shifting the work to link-time
    with jlink. When the module system was introduced we included a
    jlink plugin to generate the module graph (the Configuration) at
    link time, then a fast reconstitute of the Configutation at
    run-time. In JDK 12 it went a step further with CDS support for
    object archiving and enabling CDS by default. It improved again in
    JDK 16 with the archiving of the boot layer. The overall effect of
    all these efforts is all code to initialize the module system and
    the boot layer disappears from startup.<br>
    <br>
    I think it would be interesting to explore shifting the generation
    of the Configuration for application / child layers to either build
    time or link time. There is a lots of interesting directions to
    explore. We had many ideas in this area during JDK 9 but had to
    focus on the core system. I suspect this could be a lot more
    fruitful direction that wouldn't forsake reliable configuration.<br></div></blockquote><div><br></div><div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">While that is a very interesting topic, it is in a sense the opposite of what I'm focused on right now, which is the application container case. It is true that there is a great deal of interest in moving things towards build time for a fairly broad class of application. However, in this case I'm starting from the other end of the spectrum, where we have containers which can dynamically load and unload applications. This use case, while historical, is still wide<br><br>Your point about reliable configuration is an interesting one. We have had a concept of modules that predates Java 9 by several years. This modular concept was focused on a more relative integrity. That is to say, for a given module that is loaded, we ensure that each of its immediate dependencies is loadable, and provide an isolated visibility between modules. Within this system, we don't have to verify the integrity of the entire graph and we therefore don't actually need a concept of "layers" as defined by the JPMS (rather, layering is a natural consequence of the design). In fact we've always considered the requirement to validate the entire graph as an anti-requirement, because it doesn't actually give the user much practical benefit, while also being very costly, and it might be open-ended or even downloaded on demand, and also because the applications within a container may number between one, to dozens, to literally thousands at once. The libraries which support these applications form a complex graph of many hundreds to thousands of JARs. Some of these JARs may represent multiple versions of the same library. This is allowed and supported as an inherent property of a module system which provides isolation and only validates integrity on a local, per-module basis.<br><br>Many features in OpenJDK historically exist at least in part because of use cases like ours: for example, better class unloading support, GCs which support giant heaps, etc. The inflexibility of the JPMS in this regard is the primary reason why we (and presumably others) have not yet integrated with it. I am (and have been) trying to change that, but to do so, I believe we will need some kind of concession around service loading since that's the missing piece right now. It's clear that static (build-time-oriented) Java has a bright future, but classic dynamic (run-time-oriented) Java isn't going anywhere any time soon. Excluding one for the sake of the other is not a wise course.</div></div><div><br></div></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr">- DML • he/him<br></div></div></div>
</div>