New Adventures in Software

The Incredible Shrinking Software

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…

9 Responses to “The Incredible Shrinking Software”

  1. [...] The Incredible Shrinking Software [...]

  2. Your subhead “1995 called, it wants its RIA technology back” made me chuckle. As I watch the fuss and movement towards RIAs, I can’t help but recall when Microsoft and, to a lesser extent, Sun were accused of “balkenizing” the Web back in the mid-90s because they believed Web experiences should be as rich as the desktop. BWAAAA went the thin client/open standards crowd. Now the trend is towards Flash and Silverlight. Someone please tell me how this is ANY different from a hosted ActiveX control or Java applet???? I’m all for rich user experiences. But I think ti’s funny to see how what once once derided is now the big fat trend. Someone please explain to me how Flash and Silverlight are not proprietary? As a tools vendor, we saw the handwriting on the wall long ago. We added Web UI capabilities a few years ago, and last year, AJAX on the UI and to reduce database latency (an area that does not get enough attention/credit from developers, IMHO). That way developers don’t have to be as concerned (if at all) with download size, provided the AJAX we generate is efficient. That’s not to say that demand won’t motivate us to add other RIA technologies down the road, but right now, AJAX seems a great, platform neutral way to go.

  3. Jos Hirth says:

    Obfuscation (well, the minimizing kind) can help, but better compression can help so much more. Pack200 is supported since 1.5 and LZMAInputStream only adds about 7kb. If both compression schemes are combined (Pack200 actually doesn’t compress much on its own) you can get really impressive compression ratios.

    http://kaioa.com/svg/compression_ratio.svgz

  4. Dan says:

    Jos, good point, in fact Pack200 is the subject of my latest post :) (see http://blog.uncommons.org/2008/11/09/smaller-java/)

  5. I tried Proguard but unfortunately it generates errors instead of obfuscating or shrinking. And this altough I tested several configurations and my programs are some easy libraries (no big project) but just a few library dependencies.

    Another problem with it is that for classes dynamically loaded later on or external scripts may not work any more due to class name changes and so on.

  6. Dan says:

    Martin, it does take a little bit of trial-and-error to figure out exactly which combination of keep options is required. However, I have found that, unlike other obfuscators I tried, there is always a way to get it to work.

    As for reflection Proguard will normally detect it and warn you so that you can tweak your configuration to preserve the appropriate names.

  7. john watson says:

    I had a discussion with a developer a few months back about this sort of thing. The idea there was to use test suites to determine which code wasn’t needed and have the build system delete it.
    I was wondering about trying to recompile things like jboss, spring, hibernate, etc with just the parts I need to try and get my deployable files down to size.

  8. Dave Gilbert says:

    Hi Dan,

    Your applet has inspired me to try to put together a script that partitions the JFreeChart classes and will let you build a jar file with a smaller subset of classes that relate only to the features you want to use. I’ll keep you posted on how that goes…

    Dave Gilbert
    JFreeChart Project Leader

  9. Dan says:

    Dave, sounds great :)