views:

400

answers:

10

I'm developing a Java Applet, and reducing the size of the binary code will make the applet open faster and will improve the user experience.

Is there anything I can do to reduce the size of classes and / or jar files? I want to be sure I'm not missing obvious tricks.

I know that in the C++ world compiler options for e.g. stripping debug symbols can make a huge difference, but I've never seen something like that for Java.

+5  A: 

You can use

javac -g:none

to remove debugging information - I don't know how much difference it's likely to make though.

How convinced are you that the download time is the bottleneck? How big is the applet? Unless it's enormous, I doubt that size will make much difference after it's downloaded.

Jon Skeet
The applet is 500k excluding libraries. It's not the only thing that affects startup time, but I think it is significant enough to investigate further.
amarillion
A: 

try this tool. http://proguard.sourceforge.net/

tommaso
A: 

You could use a tool to apply code obfuscation. This will often shrink down the variable and method names and reduce the class sizes significantly. This is often done when deploying code to the J2ME platform.

teabot
+3  A: 

Proguard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions.

Reports on the proguard site show examples of the reduction, ranging from 19 to 90%.

The MYYN
+7  A: 

check out this page for some tips on how you could make your jar files smaller - http://wiki.java.net/bin/view/Games/4KGamesDesign . Even though some may not apply since you are not trying for absolute minimalization, there are some general tips that you can apply without compromising code quality.

but a summary here:

Keep your code down to one class. Each class adds the overhead of an entry in the JAR file, as well as a brand new constant pool and class list.

Keep your methods to a minimum. Each method adds overhead in the class file. All you should need is a main() method, and methods to implement the keyboard and/or mouse routines.

Don't use global variables. Global variables require special meta-data in the class to identify. Method-local variables, however, are only stack entries and cost nothing extra to use.

Use a good compressor like 7Zip or KZip to create your JAR files. The JAR utility is mostly designed for correctness, not compression ratios.

Use an obfuscator like ProGuard, JoGa, or JShrink to optimize the size of your class.

Use a single character for the class file name. This reduces its size internally, reduces the amount of info the Zip program stores, and reduces the size of the manifest.

Reference as few classes as possible. Each class you reference adds the full package and class name, plus the method signature you're calling.

Redundancy (such as using the same name for all your methods and classes and fields) improves compression ratios.

Methods made private and final can be inlined by a class optimizer.

Use the String.valueOf() method to convert primitives to strings. For example, ""+number expands to: new StringBuffer?().append("").append(number).toString() wasting a great deal of space in new class and method references.

Static strings, floats, and integers used in the source code get stored in the constant pool. As a result, the more you can reuse a static value, the smaller your class will be.

You can make liberal use of static final varaibles for constants. This will make your code more readable and ProGuard will optimize this away so there is no extra overhead.

Chii
Global variables? Java doesn't have these.
uckelman
I think Chii means class-level member variables
matt b
That is a very detailed list of things *not* to do, not even for the sake of filesize—unless it’s only for demonstrational use. :)
Bombe
Obfuscation is worth looking into if it can be done as part of the build process. But I definitely don't want to give up code readability to save a few bytes.
amarillion
these suggestions are not all applicable to all situations - they are mainly for this competition called java4k where you create a game in java under 4k of jar. But you can cherry pick one, e.g., using a better compressor than the standard jar uses, etc.
Chii
+1  A: 

As far as I can tell you can't strip symbols from Java class files, but you can shorten identifiers. However, this will probably make stack traces useless, so I don't advocate it.

However you can losslessly reduce file size by recompressing your .jar files using improved deflate algorithms from the AdvanceCOMP project (.jar archives are just plain .zip files inside).

intgr
+1  A: 

Classdepandjar is used in the Jini world to reduce jar file sizes (Jini ships around a lot of remote code, hence this requirement). It removes classes that aren't referenced from within that same jar.

Obviously there are exceptions to this (classes loaded by name etc.) and so you can accommodate these in the config. You should most likely test against your 'shaken down' jar to determine that relevant dependencies remain.

Brian Agnew
+2  A: 

pack200 (and gzip) produces much smaller files than jars (effectively zip files).

Tom Hawtin - tackline
A: 

If you use NetBeans, you can set the build script to generate a compressed JAR file in the project configuration (under Build->Packaging). Maybe not as effective as other solutions, but it's only a checkbox away. :-)

perp
A: 

Some suggestions to improve applet size:

  1. Obfuscate - Proguard was the best for overall performance for me - over 25% reduction for me. In addition it will provide decent compression during the Jar.

  2. Optimize any resources - reduce attached images using image optimizers, lower quality if appropriate.

  3. Code changes - I see that you don't really want to do this, but it's worth taking a look at your Jar files and checking how many classes are produced. The most trivial class will cost about 500 bytes. If you have lots of anonymous inner classes it may be worth refactoring.

  4. Load resources as required - Load the initial applet. Load additional resources asynchronously after starting.

Pool