-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues related to boot module layer synthesizing with closed-world approach #3733
Comments
IMO, this is a feature and not a bug. It is equally simple to construct a trivial sample application that uses reflection that passes on JVM but fails as native-image (if no configuration is provided during image build). The question is what compromise we are more willing to present to our users:
|
Btw, comparing the output of public class HelloJava {
public static void main(String[] args) {
System.out.println(java.util.Arrays.toString(Package.getPackages()));
}
} when running on the JVM compared to running as native-image gives very different results. Here also the output of |
We certainly do not want to include completely unused modules in the image heap, neither from the module path nor from the JDK. Why should a Hello World contain module information about, e.g., the Now the question is: when is a module "used". Clearly, a module is used when at least one class of that module is included. But modules also have dependencies. If I understand the module system correctly, then module dependencies are an acyclic graph. So I think when a module is used, also all of its dependencies should be in the image heap. So in the example above, But if you have another module There are also optional module dependencies ( What to do with the "unnamed" module, which automatically depends on all named modules? Not include all dependencies of course (because that would result in all modules being always included). |
Why not? The overhead is below one page in the image heap.
Because it does that when one runs "Hello, World!" with I am asking because this would mean that we need an additional config file, agent changes, etc, for the code above to work as expected. Given the low overhead of including modules into the heap, I would argue that it is not worth complicating config further. |
As I said, the example above (where there is a direct module dependency) needs to include the "library" module. So that then works "as expected". And for the case of JDK modules and application modules that are just passed in on the command line and then not used: here you need to define what "expected" means. Clearly, we also do not preserve the list of .jar files passed in on the class path. If you expect that every class, package, or module that you specified on the command line is available at run time, then you cannot use a closed-world assumption. And no, we do not need an additional configuration file for modules. When you want a module to be available at runtime, register one class of it (like the module-info class) for reflection. |
The example above would not work if we are looking for any module from the JDK. But then, for such code, one should state in the I am OK with the proposal above given that the removal of completely unused modules can be also achieved with |
Good argument! A real-world application that relies on seeing unused modules at runtime is bogus/fragile for exactly that reason. |
Thanks for the feedback! This can be assigned to me, I will enhance the boot layer module set to include required modules as well. |
Describe the issue
NI boot module layer currently only contains modules which contents are reachable after analysis. This behavior follows the closed-world assumption and is naturally translated to module system as well. However, in the case of modules, it can in some cases cause unintended results. This issue shows a simple example, with the goal to open a discussion about potential changes in the current closed-world approach when it comes to modules.
Describe GraalVM and your environment:
master
, or that it is based on a commit after the merge of [GR-30957] Implement Module/ModuleLayer substitutions #3445Steps to reproduce the issue
A simple example can be a modularized application with two modules - one of which will be a "library" module exporting a package that will be used by the "main" module.
The "library" module can be defined as:
It contains a class
core.util.WorkerUtil
with the following definition:The "main" module can be defined as:
Our main method, contained in
main.app
module, can be defined as:We can build an image of this application (in this example all jar files that are created by
javac
are located inpkg
directory):We can now verify that the assertion will hold by running the image. If we do not invoke the
useLibrary()
method, the entirecore.app
module will not be included in the image, as types from that module are not used. Re-runningnative-image
in the same way as above (however this time not invokinguseLibrary()
method), and invoking the generated executable will lead to anAssertionError
:This way modules can unintentionally break dependant modules simply by removing dependencies.
More details
For this example, the size of an executable which only contains only reachable modules (14 in this case):
11481768 B
(~11M
)For this example, the size of an executable which contains all modules on the module path (26 in this case):
11485864 B
(~11M
)From here, we can see that the difference is
4096 B
, which averages to~341 B
per module (this value correlates to the number of packages contained in the module).The text was updated successfully, but these errors were encountered: