Note: information in this Chapter is not applicable to the Standard Edition of Excelsior JET.
Excelsior JET features the Global Optimizer — a powerful facility that has several important advantages over the default compilation mode:
The Global Optimizer is integrated with the core JET compiler. By default, JET compiles applications in the dynamic link model, i.e. compiled application classes are linked into an executable that requires JET Runtime DLLs containing precompiled Java SE platform classes (see Profiles). Quite the contrary, the Global Optimizer detects the platform classes that are actually used by the application and compiles them along with the application’s classes into a single executable. Despite the resulting executable occupies more disk space as compared with the default mode, it does NOT require the JET Runtime DLLs. As a result, both disk footprint and download size of the optimized application are reduced.
The following table compares the Global Optimizer with the default compilation mode:
The Global Optimizer always produces a single executable for the whole application – you cannot split it into EXE and DLLs, which has some disadvantages as compared with the default mode:
In the default mode, the code of all platform classes is contained in the JET Runtime dynamic libraries shared between all executables in the original installation and update packages. Every executable generated with the Global Optimizer contains its own copy of precompiled platform classes. So, if an installation package includes several executables or an update package contains a new version of the executable, the total download size increases due to code duplication.
To recap, when using the Global Optimizer, pay attention to the following issues:
Switching between the Global Optimizer and the default compilation mode is quite easy so you can try both to check which mode suits best for your case.
Compiling both application and platform classes together, the Global Optimizer analyzes the entire program, thus enabling the compiler to optimize it more effectively.
When compiling an application, the Global Optimizer performs a whole-program analysis, making an approximation of actually used classes and methods. Unused platform classes are left in the bytecode form (.class files). This allows JetPackII to include those classes into the installation package in a highly compressed form /If you opt for Excelsior Installer setup on the Backend page, JetPackII compresses the non-compiled classes using the pack200 method specially designed for Java class files/ . As a result, the created package has a smaller size as compared with the default mode in which all classes are included into the package in the native compiled form.
Under circumstances, the set of actually used classes may differ on the developer’s and target systems. For example, it may depend on a flavour of the operating system, screen resolution, default system locale, etc.
However, this does not mean that the compiled application fails in such case. If the application loads a non-compiled class, it is compiled on-the-fly by the JIT compiler included in the JET Runtime. Though dynamic compilation imposes some runtime overheads, the overall application performance is almost not affected, because only a few extra classes are typically loaded /provided that a thorough test run is performed/ .
Of course, shipping classes in the bytecode form does not provide code protection for them. It is not a problem, however. Typically, the classes that need code protection are developed in your company (application classes), while the platform classes and the classes of third-party APIs (API classes) do not require protection and can be distributed in the bytecode form.
When you create a project in the JET Control Panel, it automatically separates the classpath in two groups: entries containing application classes and entries containing third-party API classes. If you select the SMART optimization preset on the Classpath page, the Global Optimizer is turned on and the Control Panel automatically enables protection for application classes and disables it for API classes. However, you can correct the default settings using the classpath grid.
Note: the more classes for which protection is disabled, the smaller size of the installation package you get.
Building an executable with the Global Optimizer includes the following steps:
The main difference from the default mode is that you are strongly encouraged to perform the test run step that is otherwise optional.
When using the Global Optimizer, the Test Run step is highly recommended. Due to the dynamic features of Java, the information about application execution, such as the set of classes loaded at run time, cannot be collected using only a static analysis. During a test run, the necessary information is collected dynamically and saved to .usg file which is then used by the Global Optimizer.
For example, consider a typical application that uses plugins and loads them via the Java Reflection API. The information about what plugins are actually loaded is known only at run time, because it may depend on user actions, configuration files, etc. Moreover, the set of loaded plugins can vary between different runs. Without a thorough test run, the Global Optimizer has no actual information about what plugins are executed and thus the quality of optimizations applied to them is reduced. As a result, performance and response time of those plugins will be low.
Note: Even if your application’s code does not use plugins, Java Reflection API and JNI, you still have to perform a test run, because these mechanisms are used by the Java platform classes. For instance, Reflection is employed during Swing initialization, so most Java GUI applications implicitly use it.
You can perform a test run in one of three ways:
The recommended way is perform a test run from within the JET Control Panel. All you need to do is just follow the instructions on Step 2.
The information below is intended for users who, for some reasons, wishes to perform a test run manually. For example, it is useful if you want to stress test the application with the different input data or add the test run step to night build.
If you had already compiled your application into an executable, you enable the test mode by setting the system property jet.usage.list=MyApp.usg.
Otherwise, you can run xjava utility with this property specified on command line, for example
xjava -Djet.usage.list=MyApp.usg -cp MyApp.jar MyMain
If the jet.usage.list property is set, execution of your application is qualified as a test run. That is, upon application exit, the collected information will be written into the specified .usg file created in the application’s working directory. In the examples above, the information will be saved to MyApp.usg.
You may re-run your application as many times as you wish, supplying, for instance, different input data. In this case, the previously created .usg file is not overwritten, but new information is added to it.
During a test run, stress test your application to achieve the largest possible code coverage. Thorough testing the application helps Excelsior JET collect more information about its execution and better optimize it.
Note: a .usg file is generated automatically and should not be edited by hand.
In JET Control Panel, you turn on the Global Optimizer by selecting the "Smart" optimization preset (see Optimization presets). As a result, the Global Optimizer is enabled and properties of all classpath entries in the classpath grid are set to the values recommended for this mode.
If you are editing your project file manually, add the following to the project file:
You can add the executables optimized with the Global Optimizer to the installation package in the same way as executables compiled in the default mode. Namely, on Step 2 of the JetPackII tool, add the executable to package files and all necerssary the JET Runtime files will be added automatically.
However, it is not recommended to mix such executables with those compiled in the default mode in one package, because it significantly increases the size of the resulting package.
Moreover, it is recommended to use the Global Optimizer only if you have exactly one JET-compiled executable in the package. Otherwise the size of the package may increase because some platform classes are included into each executable.
Note: If you need to distribute more than one application in the package, consider using the multi-app executables (see Multi-app executables).
Note: By technical reasons, it is impossible to include runtime utilities to a package that contain executables compiled with the Global Optimizer. This limitation will be removed in future versions of Excelsior JET.