Super Prev Next

Application considerations


Super Prev Next

Runtime Selection

Note: Information in this section is applicable to Excelsior JET Professional Edition only.

Excelsior JET VM comes with multiple implementations of the runtime system, optimized for different hardware configurations and application types. It enables your application to effectively utilize the computing power of systems that support parallel execution /Examples are multi-processor servers, multi-core CPUs and CPUs that support Hyper-Threading Technology/ , thereby improving performance.

This section describes the available runtime systems and helps you select the proper runtime for your applications and target system configurations.


Super Prev Next

Available runtimes


Super Prev Next

Desktop Runtime

The Desktop Runtime is suitable for applications that typically run on conventional desktop and notebook computers. It is optimized for single-CPU systems, including those based on Hyper-Threading-enabled processors and dual-core desktop chips. Zero runtime fee makes it the best choice for rich clients and other desktop applications.


Super Prev Next

Workstation Runtime

The Workstation Runtime is a scaled up version of the Desktop Runtime targeting technical client applications that require high computing power. Examples are visualization and engineering design tools, which often run on high-end graphic workstations. The Workstation Runtime can operate effectively on both single-CPU and dual-CPU boxes.

You may freely use the Workstation Runtime for development, but production and redistribution uses require payment of a runtime fee.


Super Prev Next

Server Runtime

The Server Runtime fits best for highly concurrent server applications. It provides out-of-the-box performance and scalability and takes full advantage of multi-processor hardware. Development use is free, but deployment in a production environment is subject to runtime fee.


Super Prev Next

Classic Runtime

The Classic Runtime is technically a restricted version of the Desktop Runtime. Its use makes sense only if your application does not run several heap-intensive threads in parallel. In that case it may save a few percent of CPU and memory resources. No runtime fee applies.

The Classic runtime was the only option in Excelsior JET VM prior to version 3.7, hence its name. It is the only option in the Standard Edition.


Super Prev Next

Which runtime fits best for my application?

Basically, you select an Excelsior JET Runtime depending on the type of your application and hardware configurations of systems to which it will be deployed. To make the right choice, follow the recommendations below.


Super Prev Next

Server-side applications

If your server application will be deployed to high-end multi-processor machines, opt for the Server Runtime. Other Runtimes are not optimized for N-way systems so choosing them would significantly degrade the throughput of the server. Read more about licensing terms for the Server Runtime at
http://www.excelsior-usa.com/jetfees.html.

For low-end uniprocessor servers, the royalty-free Desktop Runtime fits best.


Super Prev Next

Client-side applications

In most cases, the Desktop Runtime is the optimal choice. Nevertheless, you may prefer other options in the following cases:

The Workstation Runtime is more suitable than Desktop if your application is designed to work faster on powerful dual-CPU workstations. Read more about licensing terms for the Workstation Runtime at
http://www.excelsior-usa.com/jetfees.html.

The Classic Runtime’s overheads on memory allocation and garbage collection are lower than those of the Desktop Runtime so its use may slightly improve application performance and reduce its memory footprint as compared to the Desktop Runtime, but only if your application never runs several heap-intensive threads in parallel. If you are not completely sure whether it is the case, use the Desktop Runtime.

You may experiment with each runtime flavor as described in the next section.


Super Prev Next

How do I enable a particular runtime?

You select the runtime when compiling your application. The JET Control Panel shows the available RT options on the Target page. If you use the command-line interface to the JET compiler, specify the JETRT equation in the project file:

    -JETRT=WORKSTATION

Finally, if you run your application via the xjava launcher, use the -Xrt option to select the desired runtime (see Options):

    xjava -Xrt=server -jar MyServer.jar

You may also select the runtime at application launch time specifying the jet.rt property in the JETVMPROP environment variable (see JET runtime properties):

    SET JETVMPROP=-Djet.rt:classic
    MyApp.exe

Note, however, that the jet.rt property can only force lower-end runtimes /In the sense of this order: Classic < Desktop < Workstation < Server/ than the runtime selected at compile-time. For instance, if you chose the Desktop Runtime when compiling your application, you may force the Classic Runtime during its launch, but not the other runtimes. If you wish to test your application against all runtimes, select the Server Runtime in the project and then select other runtimes using the jet.rt property as desired.


Super Prev Next

Code performance

If you used any optimizing compilers before, you must have experienced a situation when a particular combination of the many available optimization control options results in incorrect code being generated by the compiler for your program, or when the program only works properly when compiled with debug information generation enabled. The reason is that a compiler with dozens of optimization control options is extremely difficult and expensive to test, as the compiler manufacturer has to check all possible combinations of options, so no vendor does that.

Fortunately, this is not the case with JET. Unlike many other compilers, JET always optimizes code to the maximum extent possible. Even enabling generation of debug information to ease field engineering does not affect the output code. The only two optimizations that may be disabled or adjusted are stack allocation of objects and inline expansion of methods, because they can negatively affect scalability (see Number of threads) and code size of the resulting program.

To get the maximum performance, do the following:

  1. Enable stack allocation of objects: Stack allocation is enabled by default. See Optimizations and Number of threads for more information.
  2. Enable inline expansion of methods: See Optimizations and also comments below for details.

Inline expansion should be used with care. It allows the compiler to substitute a method in-line, if that method is declared as final or if compile time analysis confirmed safety of such substitution. As a rule, enabling inline expansion results in faster but bigger code. However, the effect of this optimization depends on the programming style (sizes of methods, etc). You may control inlining aggressiveness using equations INLINELIMIT and INLINETOLIMIT in the project file, or by selecting one of the presets in the Inline expansion list in the Control Panel.


Super Prev Next

Scalability


Super Prev Next

Multiprocessor systems

JET is fully SMP-aware, so your compiled applications will scale to multiple processors automatically. However, you should select the Workstation or Server RT to enable the most effective utilization of several CPUs (see Runtime Selection). You may wish to fine tune the garbage collector as described in Parallel hardware.


Super Prev Next

Number of threads

Excelsior JET runtime maps Java threads directly onto native operating system threads. Windows reserves the same amount of address space for the stack of each thread of a particular process, which is retrieved from the size of stack reserve field of its EXE header.

The default size of stack reserve is about one megabyte, which basically means that if your program attempts to run 1,000 threads simultaneously (which is not unusual for server-side applications), their stacks will claim one gigabyte of the process’ virtual address space, of the total of four gigabytes. Given that some part of the virtual address space is reserved by the operating system (Windows reserves half of it, i.e. 2GB), one process cannot run more than a few thousand threads simultaneously with that default setting.

An attempt to run too many threads simultaneously in a Java application results in OutOfMemoryError. Waste of address space for thread stack reserves also effectively limits the amount of memory that the memory manager may allocate from the OS and thus may also cause OutOfMemoryError.

To reduce the default stack size and thus improve the scalability of your application with respect to the number of threads:

This is equivalent to setting the -Xss option of the standard Java launcher.

Another thing to consider is that enabling stack allocation of objects increases the compiled programs’s stack size requirements, negatively affecting its scalability. Therefore, you may wish to disable this optimization by unchecking the Allocate objects on the stack box on the Options page (see Optimizations) or turning the GENSTACKALLOC option off in the project file. This would enable you to further reduce the thread stack size as described above, thus letting your application run more threads simultaneously at the cost of minor performance loss.


Super Prev Next

Java system properties

A Java launcher allows you to set a system property using the -D command-line switch, for instance:

    java -Dp1name -Dp2name=p2value MyApp arg1 arg2

A JET-compiled application is a conventional executable file that is run by itself:

    MyApp arg1 arg2

so there is no place to set a property on the application’s command line.


Super Prev Next

How to set system properties

JET provides three ways to set system properties for your compiled application:

At compile time:

You may hardwire system properties into the resulting executable as follows:
At install time:

You can override properties hardwired into the deployed executable, if any, taking into account the target system parameters. See Step 3: Setting Up Standalone Resources and Java System Properties and xbind for details.
At launch time:

Use the JETVMPROP environment variable. For the above example, you would use the following commands:

    SET JETVMPROP=-Dp1name -Dp2name:p2value
    MyApp arg1 arg2

Warning: The JETVMPROP environment variable is intended to be used during development and field engineering. Normally, you should hardwire the necessary system properties into the executable at compile time or install time as described above. If you need to override the hardwired properties at launch time, use a batch file for launching your application. Never set the JETVMPROP environment variable globally (i.e. in the Windows registry or AUTOEXEC.BAT) on enduser systems as it may cause other JET-compiled applications to misbehave.

Notes:

  1. The colon character has to be used between property name and value whereas Java launcher’s command line syntax for defining properties has the equals sign after property name. The reason is that many Windows command interpreters, including standard Windows 95/98 ones, do not permit more than one equals sign in a SET statement.
  2. On application startup, properties set through the JETVMPROP environment variable are merged with hardwired properties. If a particular property is set using both methods, the value retrieved from the environment variable shall prevail.


Super Prev Next

JET runtime properties

The JET runtime recognizes the following properties:

jet.gc.heaplimit:size[k|m]

Sets the maximum heap size to the given amount of bytes (kilobytes or megabytes respectively if either of the suffixes k or m is present), overriding the compile-time heap size setting. Setting size to zero enables adaptive heap size. See Memory management for more information.

jet.gc.ratio:ratio

Specifies the maximum proportion of CPU time to be allocated to the garbage collector at runtime, in 1/1000ths. See GC ratio for details.

jet.rt:flavor-name

Select a specific JET Runtime. Valid values of flavor-name are classic, desktop, workstation, and server.

See Runtime Selection for details.

jet.gc.threads:N

Sets the maximum number of concurrent threads that may be used for garbage collection. By default, N equals the number of processors on the system. See Parallel hardware for more information.

jet.jit.cache

Enables caching of JIT compilation results. See Using the mixed model for more information.

jet.jit.cache.dir:path

Designates path as the JIT compiler cache directory. See Using the mixed model for more information.

jet.log.dlls

Logs names of DLLs loaded by the application at run time into a file.

jet.stack.trace

Enables stack backtracing facility. See Stack trace for more information.

jet.jit.optimizing

Forces the optimizing JIT compiler. See JIT compiler selection for more information.

jet.jit.fast

Forces the fast JIT compiler. See JIT compiler selection for more information.


Super Prev Next

Memory management

Excelsior JET lets you define the policy of memory management to be used for your Java application at run time. This section describes a few simple mechanisms that you can employ to set an optimal balance between performance of the application and its memory footprint.


Super Prev Next

GC ratio

Ideally, an application should work fast enough and consume as few memory as possible. In practice, there are always trade-offs between application performance (or throughput) and its memory footprint. What’s especially important is that performance and memory requirements are application-specific. For one program, performance is critical, whereas low memory footprint has more value for the other. Put simply, one size does not fit all.

Fortunately, the JET Runtime lets you fine tune the performance/memory balance for your Java application. For that, you just set a ratio in which the Runtime will portion out execution time between the two tasks: execution of the application’s code and garbage collection. This technique is simple and effective:

You can do that by specifying the GC ratio setting to the JET Runtime. Its value is the tenths of percent of total CPU time that may be spent for garbage collection. For example, the default GC ratio is 1.1% which means that GC will normally take the percentage in total execution time. You can vary the GC ratio as follows.

The maximum GC ratio you can set is 40.0%.

Note: changing the default GC ratio is available only in the Professional Edition of Excelsior JET.

The default setting (1.1%) is biased to performance and, therefore, may cause excessive memory consumption in some cases. You can experiment with your Java application by fine tuning the GC ratio. Often, increasing the value by several units may noticeably reduce memory footprint. That’s why the unit of measure is 1/10th of percent not a whole percent.

One might question: what reduction in memory footprint can I expect when increasing the GC ratio by X%? In general, it depends on two factors: how much garbage your application produces and how fast it does that. Thus, the answer is specific to a particular application.

Note that under certain circumstances, the JET Runtime is unable to meet the GC ratio requirement. For example, if a Java application allocates objects very intensively and amount of available physical memory is low, more CPU time may be spent in the garbage collector regardless of the ratio specified.

Finally, you may set the GC ratio to 0 to entirely disable the mechanism (it’s not recommended, though.) In such case, GC is automatically invoked only if the JET Runtime is unable to serve a regular request for object allocation due to memory constraints as described in the following sections.


Super Prev Next

Maximum heap size

You may specify the maximum amount of heap memory that your application is allowed to allocate at run time /The respective command line parameter of the standard Java launcher is -Xmx/ :

To override the compile-time setting, you may set the system property jet.gc.heaplimit, e.g.

     -Djet.gc.heaplimit:35m

You need to specify the maximum heap size only if you do not want the Java heap to exceed certain upper bound in any case. On the one hand, it may be useful to reduce application memory footprint. On the other hand, it may compromise performance of your application. For example, it might work more effectively when using large Java heaps on the target machines that have high RAM capacity.

New in JET 4.0:

The default value of the maximum heap size is 0 which means Adaptive. In this mode, the Java heap is only bounded by the size of Virtual Address Space that varies from 2 to 4GB, depending on the underlying operating system. But do not be afraid. It does not mean that your application will take gigabytes of memory at run time. First, the JET Runtime checks the GC ratio which effectively damps inflation of the heap. Moreover, the runtime constantly monitors the amount of available physical memory as described in the next section.


Super Prev Next

Handling low memory

New in JET 4.0:

As a rule, it’s hard to determine the "right" application memory settings because they are specific to a particular target system. For instance, you consider a box equipped with 256MB of RAM as a "typical target system" but some customers are proved to be still using 128MB machines. Another example is a system under heavy workload: imagine that your application runs simoultaneously with a couple of other programs hungry for memory. Anyway, your application must work, more or less efficiently.

To address these problems, the JET Runtime considers the amount of available physical memory in the system to schedule garbage collection. If low memory is detected when allocating an object, GC is activated to avoid unnecessary swapping RAM pages to the hard disk. Of course, it leads to more frequent GC invocations and penalizes application performance. But it’s a good alternative to tremendous overheads of swapping memory to and fro.

However, if the runtime detects that application execution has degraded to sole garbage collection or it’s unable to allocate an object even after GC invocation, the physical memory boundary is crossed. The JET Runtime augments the Java heap with the amount of memory enough to serve the allocation request plus some decent gap necessary for further operation. Often, this move helps to clear the air. The operating system reacts to the event and fetches memory, e.g. from the system cache, so that the application continues running smoothly.

You have control over the JET Runtime with respect to crossing the physical memory threshold. To override the default behavior

As a result, OutOfMemoryError will be thrown instead of using virtual memory to increase the heap. This mode is useful if you suspect that your application has performance issues due to not enough memory in the system. You may easily prove or disprove that by disabling the default policy and handling OutOfMemoryError exceptions, if any.


Super Prev Next

Parallel hardware

Professional Edition only:

If your target systems support parallel execution on single or multiple CPUs, select an appropriate version of the JET Runtime as described in section Runtime Selection. The right choice of Runtime has a great impact on performance of applications that use the Java heap intensively.

Moreover, on the parallel hardware, the garbage collector runs in multiple threads to reduce collection pauses. By default, the total number of concurrently working GC threads equals the number of CPUs reported by the operating system. However, you may reduce this number for optimum system performance, e.g. if you want one or more CPUs to be available to some native threads or processes running at the same time.

For that, set the value of the jet.gc.threads property to the maximum number of GC threads. For instance, to make the garbage collector use at most two threads, specify the following setting:

   -Djet.gc.threads:2


Super Prev Next

Application appearance

To customize apearance of your application, you can

You may control these features at compile time using either JET Control Panel or command line interface to the JET compiler as described below.


Super Prev Next

Icon

To assosiate an icon with the resulting executable, do the following.


Super Prev Next

Console window

By default, the standard input/output/error streams are enabled to let the application print messages to the console. As a result, when starting your GUI application, you see a black console window opened in addition to the application’s frames. If you do not want the window to appear, you can suppress it /In Sun JDK, you would use the javaw launcher for that./ for the application:


Super Prev Next

Splash screen

New in JET 4.0:

If startup of your application takes longer than you would like it to do, the thumb rule is to show a splash screen. It definitely relieves the loading process from the end user’s perception, moreover, the splash may contain information about your product and company.

Programmatic efforts of implementing a splash screen with the Java platform API often do not pay back. The problem is that the loading of the required platform classes takes time itself so the effect of momentary startup disappears.

To help you easily solve the problem, Excelsior JET features InstantSplash, a native implementation of the splash screen functionality. It enables you to add a splash to your application without writing a line of code. All you need to do is to specify the necessary splash settings to the JET Runtime.

Note: InstantSplash is available only in the Professional Edition of Excelsior JET.


Super Prev Next

Displaying a splash

The current implementation of InstantSplash supports only bitmap images (the BMP format.) You may convert images from other formats to BMP using a third-party image processing tool.

To assign the application a splash screen image, do the following:

The splash will quickly appear at the very startup of the application (hence the name InstantSplash.)


Super Prev Next

Suppressing a splash

The splash screen disappears immediately if the use clicks on it. Otherwise, the JET Runtime controls how long the splash stays on the screen. It is hidden automatically as the application opens any GUI frame. Note that it will do work, irrespective of what particular API (JFC/Swing, SWT or something else) the application uses to open windows.

You may opt for closing the splash only for a particular window, depending on the windows’s title. For that, you need to specify a prefix of the title as follows.

As a result, the splash will be closed when opening a window whose title string starts with the prefix.

Note: If you did not specify a prefix and did not suppress the console window for your application (see Console window), the splash sreen disappears when the console is opened. If this behavior is not desirable, specify a window’s title prefix to resolve the issue.

Finally, you may wish to delay splash disappearance, e.g. to let the user enjoy your artwork. For that, specify the number of seconds you want it to stay on the screen:

If a delay is set, the splash works as follows. It appears at application startup and stays on the screen for the specified time /Unless the user clicks on it, of course./ . After that, the selected "auto hide" policy has effect. If the window has been already opened, the splash disappears; if not, it remains on the screen until the respecive window will be opened.


Super Prev Next

Stack trace

By default, Throwable.printStackTrace() methods print a few fake elements, because stack tracing is disabled in the JET Runtime. However, some third-party APIs may rely on stack trace printing. One example is the Log4J API that provides logging services.

The JET Runtime supports two modes of stack trace printing: minimal and full. In the minimal mode, line numbers and names of some methods are omitted in call stack entries, but class names are exact. In some cases, it is enough for the stack trace-dependent API to work, e.g. Log4J operates flawlessly in this mode.

Note: Enabling stack trace may negatively impact performance, if exceptions are thrown and caught repeatedly.

In the full mode, the stack trace info includes all line numbers and method names. However, enabling the full stack trace has a side effect of substantial growth of the resulting executable size (approx. by 30%).


Super Prev Next

How to enable stack trace

In the JET Control Panel, you enable stack trace on the Target page (see Stack trace support).

You may also select the stack trace mode via compiler options and run-time properties. To enable the minimal stack trace, set the property jet.stack.trace:

    -Djet.stack.trace

To enable the full mode, in addition to setting the property, toggle the GENSTACKTRACE option ON in your project file

    +GENSTACKTRACE

and re-compile your application.


Super Prev Next

How to disable stack trace

For security reasons, you may wish to completely disable stack trace output in the end-user version of your application. To do that, set the option DISABLESTACKTRACE ON in your project file:

    +DISABLESTACKTRACE


Super Prev Next

Assertions

In a JVM, assertions are disabled by default, but may be enabled for the entire application or for particular classes at launch time using the java command’s switches -ea, -da, -esa, and -dsa. With JET, if you enable assertions using the same switches in the JETVMPROP equation in your project file:

    -JETVMPROP=-ea:com.MyCompany.MyPackage

or control them at launch time using the JETVMPROP environment variable:

    SET JETVMPROP=-ea:com.MyCompany.MyPackage
    MyApp.exe

JET also supports enabling and disabling assertions programmatically at run time.


Super Prev Next

Resource packing

The JET compiler is unable to determine if your application uses any particular resource files, such as images or audio clips. If your application classes are put together with resources and placed into one or more jar files, the compiler is capable of packing such jars into the resulting EXE or DLL, almost like that is done for native applications. The JET Runtime will load resource files from those packed jars during execution as if they were separate files. No changes in your application’s code are required to make this work.

Using the JET Control Panel, you may enable/disable resource packing for particular jars as described in Working with program’s resources. In the project file, you may enable resource packing for all jars at once or completely disable it by setting the option BINDRESOURCES ON or OFF, respectively.

By default, the JET compiler makes temporary copies of the jars being packed, removes class files from them and then packs such "filtered" jars into the executable, assuming that the contained classes were precompiled. However, in the Mixed Compilation Model you may wish some classes to be loaded dynamically. Also, there are APIs (e.g. Java Crypto Extension) that require class files to be available at run time. To pack the entire jars (both resources and classes) to the resulting executable, use the JET Control Panel as described in Working with program’s resources or set the option BINDCLASSES ON in your project file, for instance:

    % MyApp.prj
     .  .  .
    -bindresources+    % Pack resources only,
    -bindclasses-      % do not pack classes into the executable
     .  .  .
    !module MyApp.jar

If the resource files required for your application are not placed into jar files, or you cannot use resource packing for some reason, set the CLASSPATH environment variable to point to the respective directories and jars, thus enabling the JET Runtime to find those resources. You might prefer to use a batch file for that:

    REM RunMyApp.bat
    SET CLASSPATH=MyAppRes.jar;.\res
    MyApp.exe

Alternatively, you may set the standard system property java.class.path:

    -Djava.class.path:MyAppRes.jar;.\res


Super Prev Next

Character encodings

When creating a profile, JET precompiles the Java 2 classes that are needed for input and output of characters in national encodings into a set of DLLs. The idea is to place support for rarely used encodings and encodings that require large conversion tables (such as Chinese) into separate DLLs, so as to reduce the disk footprint of compiled applications that do not use some or all of those encodings.

If your application may need to use national encodings, make sure to include the respective locales into the installation package as described in Step 4: Selecting Optional JET Runtime Components.


Super Prev Next

Intellectual property protection

Optimized native code produced by JET is about as hard to reverse engineer as code produced by leading C++ compilers. This will not save you from crackers (as you know, they are used to crack C++ programs), so you may need to employ a third party solution to prevent illegal use of your application. But the understanding of your code will become a much more sophisticated and time-consuming task, so steailng your algorithms and know-how will be more difficult and expensive.

In that regard, the only major difference between executables created by JET and C/C++ executables is that the former contain Java reflection information for all classes, methods and fields. If your application does not use reflection, you may run your classes and jars through an obfuscator that would assign meaningless names to classes, methods and fields before compiling your application with JET.

Note: When using an obfuscator with JET, please make sure to force it to leave the bytecode instructions intact. Obfuscation of bytecodes has serious negative impact on performance of the native code produced by JET from those bytecodes.

The reflection information is also used for stack trace output.


Super Prev Next

Bytecode consistency checks

On a virtual machine, if a certain class is imported but never used during program execution, i.e. it is never instantiated, none of its static methods are called, and none of its static fields are accessed, then no attempt to load that class would occur and therefore the program would execute normally even if the respective class file is not present on the system or cannot be reached by the VM.

Similarly, if a class does not contain a particular method or field that is referenced in another class, execution on a virtual machine would fail only when and if control reaches the code referencing that absent field or method.

Being an ahead-of-time compiler, Excelsior JET analyzes the entire compilation set and thus is able to detect such inconsistencies. By default, they result in compilation errors. However, when an inconsistency is detected in bytecode that is not under your control, such as a third-party class library, you usually do not have a chance to remedy it quickly. If you encounter such problem, contact the vendor who supplied the inconsistent bytecode, and toggle the respecitve JET options to make the compiler treat bytecode inconsistencies as warnings:

Note: In some applications, imported classes unavailable at compile time become available at run time. JET may handle this situation properly if you enable the reflective shield facility of the Mixed Compilation Model.


Super Prev Next

Baseline compilation

In some cases, the main JET compiler may fail to compile a particular method due to lack of memory or inability to restore the method’s hihg-level structure required for optimizing compilation, which may be caused by bytecode obfuscation. To cope with it, the main compiler invokes the so called baseline compiler for such methods. The baseline compiler implements only a few simple optimizations, and thus is able to compile any verifiable bytecode.

If the baseline compiler was invoked at least once during compilation of your project, the main compiler issues a message about the number of methods processed by the baseline compiler. Additionally, it logs the information about the methods compiled with a lower optimization level. The log file, having the executable’s name and the ".vaz" extension, is created in the current directory.

If baseline compilation occurs during compilation of your project, we would appreciate if you e-mail us the resulting ".vaz" log file along with the .class files listed in it. Doing that, you help us improve the quality of our product.