This chapter discusses several ways to reduce the download time of network-based (intranet and Internet) applications, including the use of javac compiler options, Java Archive (JAR) files, commercial packaging utilities, and more.
javac -g:none option when compiling the final version of your program. This
strips all debugging information from the class files. Running a quick test with the
Metalworks JFC demo (included in the SDK) shows about a 13 percent reduction
in class file size by using this option, as shown in Table 12-1. Using the -g:none
option also results in a slight reduction in RAM footprint.
The downside is that if your customers experience problems in the field, the problems can be slightly harder to debug. For example, stack traces from exceptions won't contain line numbers.
The Uncompressed Size row contains the sum of the Class File Size and the Resource Size values. The JAR Size row is the size of the compressed JAR, which includes both the classes and resources. As you can see, removing the debug information and saving the program in a JAR file results in about a 38 percent reduction in the number of bytes downloaded to run this program.
To demonstrate the effectiveness of JAR files, the SwingSet demo applet was rebuilt and deployed two ways. First, all of the individual classes and resources were loaded into directories on a web server. Second, all the classes and resources were packed into single JAR file. Table 12-3 shows start-up times for several runs of the applet. For this test, a PC client was used to download the applet from a Solaris server running Apache web server on a 10base-T LAN. The times were measured with a stopwatch.
When the applet is deployed with a JAR file, the start-up time is more than six times faster. The improvement is even more pronounced in the worst-case scenario. These results are representative of the improvements in download times that result from using JAR files. As always, however, the results can vary widely depending on the particular circumstances.
InputStream in = new FileInputStream("MyFile.txt");
However, if MyFile.txt is contained in a JAR file along with the class trying to
access it, this code doesn't work. There is no longer a stand-alone file with the
specified name; it's simply an entry in the larger compressed file.
To get around this problem, you need to use the Class.getResource and Class.getResourceAsStream methods. For example, to access the contents of MyFile.txt, you could use the following code:
InputStream in = this.getClass().getResourceAsStream("MyFile.txt");
See the documentation for Class for more information about the getResource
methods.
Generally, these tools work by analyzing your class files and stripping dead code in a fashion similar to a traditional linker tool. They also modify the class files and shorten the names of fields and methods. For example, a method called getCustomerAddress might be shortened to simply a. This reduces the size of the class files and the JVM constants pool at runtime. There are many reports of developers getting 30 to 70 percent reductions in program size by using these packaging tools. Using a packaging tool can also reduce RAM footprint, though the reductions are usually fairly small.
Before deciding whether to use a packaging tool, be aware that some of these techniques are difficult for an automated tool to perform in a system that supports reflection and dynamic class loading, as the Java language does. For example, if the tool changes the name of a method that you try to look up with reflection, your lookup will fail. Some of the commercial tools have mechanisms to help you deal with this, but they often require manual intervention.
Another consideration is that the obfuscation of your code can make field debugging more difficult. For example, stack traces are often very useful in isolating bugs. After compression/obfuscation by one of these tools, however, the stack trace might no longer contain the original method names.
The claims that some tools make about improving program execution speed typically apply to code running in an interpreted environment. The techniques applied by these tools are much less compelling in an environment with a JIT-all of the speed optimizations available to static packaging tools are also available to JIT systems. Today's code generators currently implement many of these optimizations, and more and more of these optimizations will be implemented in the future. Obfuscators can actually make it harder for JITs to figure out how to generate optimal code, so it's important to consider your target environment when deciding whether or not to use a packaging tool.
Overall, packaging tools are useful in certain situations, particularly if you are very concerned about application size. You should evaluate these tools with your own code and develop benchmarks for the performance aspects that are important to you. When evaluating the results, keep the concerns related to reflection and dynamic class loading in mind-even if you aren't using these features right now, you might want to in the future. Before making any final decisions, discuss these issues and any other concerns you have with the product vendor.
These dynamic downloading products generally require that you run a separate custom server process on the same machine as your web server. When a client requests your applet, a specially constructed small applet class is downloaded instead. This applet class, called a stub, then downloads the rest of your classes by making a connection (using a custom protocol) to the custom server process. This process is illustrated in Figure 12-1. Since the class file server doesn't have to use the HTTP protocol, it can download the classes much more efficiently. This type of system can also download classes in the background while the user performs other tasks.
While systems like this are new, they do show promise. The main drawback is that they require an additional process to be run on the web server, which is not practical in all environments. If the custom process can be run in your deployment environment, however, you might want to consider this option to maximize start-up performance.
Dynamic class loader configuration