It may not seem important to those of us who develop server-side Java software, but size matters. If you distribute your software on CD or DVD, you aren’t going to worry about 10 megabytes here and there. The only Java developers who tend to put as much thought into optimising for size as they do into optimising for performance are those that work with JavaME and its constrained environments. However, network-launched software, such as applets and Web Start applications, can suffer greatly from bloated binaries too.
In an era when users are used to interacting with AJAX web applictions and snappy Flash-powered content, a start-up time that rivals that of a cassette game on a C64 is going to set your application apart for all the wrong reasons. Of course, maybe your software is so good that it doesn’t matter about the load time and people will use it anyway. Then you have another problem. If you aspire to have a huge number of users for your huge application, data transfer costs are going to bite.
1995 called, it wants its RIA technology back…
So where am I going with this? If you’ve been following along at home, you’ll know that I’ve been playing around with applets again recently. Version 1.4.3 of this applet (the last build of its initial incarnation, circa 2002) weighed in at 20.9 kilobytes. Version 2.0.3 (the last build from the 2005 rewrite) was a relatively bloated 39.7 kilobytes, but still smaller than many of the image files that people embed in their web pages. But version 3.0 was/is going to be much more ambitious. More features means more code. And since I’d finally be giving up on AWT and moving to Swing, I really had no excuse not to replace the horrific custom graphs I’d hacked together for version 2.
Every Swing developer knows that if you need graphs, there’s really only one place you need to look: JFreeChart. JFreeChart does everything you could ever possibly need to do with charts and graphs. It does it well and even looks pretty good. You can tweak just about everything in order to get exactly what you are looking for.
Your library is so fat it’s got its own postcode
There was just one problem with JFreeChart: its size. 1.6 megabytes is not huge in most contexts, but something about having a 50kb applet towing a 1.6mb dependency offended me. Perhaps it was because it made my contribution to the whole a lot less significant, but it seemed to me a lot like a bicycle pulling a caravan.
I could have just accepted it as a fact of life. Good, comprehensive libraries are unlikely to be small. Broadband users would probably be able to accept the slightly longer start-up, but any dial-up users would give up long before they’d get to see anything.
So I looked at the alternatives. Most were smaller, some were ugly and some seemed a bit too basic. A couple looked like feasible replacements but, other than the size, I was happy with JFreeChart. Would I be able to get the results I wanted with these more limited libraries? I’d also have to spend some time figuring out how to use them. As I saw it, there was only one solution. JFreeChart would just have to become smaller.
It was pretty obvious that there was ample scope to achieve a significant reduction in JFreeChart’s size. As already mentioned, JFreeChart is very comprehensive. It supports several different types of charts, customisable renderers and all sorts of other optional stuff. My applet was using only a small fraction of this functionality (line graphs and pie charts). The rest of it could go.
The labour-intensive approach would have been to check out JFreeChart’s source code, start deleting code and hack around until something smaller emerged (and hopefully compiled). Too much effort for me. Which is where the “Incredible Shrinking Software” of the title comes in…
Enter Proguard
You may already be familiar with Proguard. It’s arguably the premier open source obfuscator. If you’ve ever wanted to make your Java software difficult to reverse-engineer, then you’ve probably already used it. But obfuscation is only one of two complementary functions that Proguard performs. The other is shrinking.
Obfuscation and shrinking are inextricably linked since both involve removing unnecessary information from an application’s compiled binaries. Java class files contain information that is not necessary to run the code, JAR files contain classes that you don’t use, the classes that you do use contain methods that you will never call, and all those descriptive identifiers you used are way too verbose.
The low-hanging fruit of class file shrinkage is the debug information inserted by the compiler. This includes the line number table that is used to insert something more useful than “unknown source” into exception stack-traces. You can simply instruct the compiler to omit this data (-g:none
) and the class files will be smaller. The downside of this is that the information won’t be there if you need it.
Proguard goes much further than this though. You give it one or more entry points (in this case a class that extends Applet, but it could be a class with a main method, or something else). From this, Proguard finds code from the input JAR(s) that is definitely not used and removes it. In addtion, where it won’t break anything, members are renamed with shorter names, such as ‘a’ and ‘b’, resulting in further reductions in code size (again at the expense of easy debugging – stack traces will have neither meaningful names nor source code line numbers).
How low can you go?
So, how small did I make JFreechart? Well, I cheated slightly by reverting from version 1.0.11 to version 1.0, which had all the functionality I needed but was only 1.3mb in size. With my applet code weighing in at just over 100kb unobfuscated, the combined applet + JFreeChart size was 276kb after shrinking, a total size reduction (for applet and library combined) of about 80%.
Pretty good, hey? Still bigger than I’d like though. Proguard has taken me as far as it can, but 276kb is not the limit of my ambition. There are still further reductions that can be made without sacrificing functionality. To be continued…