Mar 15, 2010

Use ImageLoader with extra caution

The ImageLoader class of eSWT and SWT is a utility class for loading and saving images. At a first glance, it is a very useful little utility class. Unfortunately, it is one piece of SWT/eSWT API that gives the implementation teams a performance headache. SWT is a well performing API because it delegates most of the work to the native services. eSWT implementation also follows this legacy and because they are meant to run on more resource constraint environments they take it a step further.

Unlike the rest of the SWT, the meat of the ImageLoader is actually implemented on Java, SWT packs Java implementations of all the image codecs that it supports. According to some, Java implementation is around 20 times slower when loading an image compared to an image loaded by native means. For the best image loading performance, it is recommended to use one of the Image constructors, which loads the images natively. This advice holds true for eSWT applications as well. Do not use the ImageLoader for loading images because it will not only be slower but will also consume more memory.

So why do even the eSWT implementations fail to optimize ImageLoader? ImageLoader has a misleading name. In practice ImageLoader has nothing to do with Image it actually loads and saves ImageData. While doing that it exposes the ImageData it loads or saves on a public field. This gives no choice to the implementation but to make the whole data available up front. Furthermore, ImageData also exposes all its fields and that also has to be initialized fully when created. So what happens when on a typical scenario of loading and using an image through ImageLoader? First, the whole ImageData is loaded into these fields. This reading and encoding is done on Java and is slower. Then this data is passed to the native toolkit which also doubles the amount of memory used for that image at least until the ImageData is released. Using Image constructors works around both defects, image is loaded and encoded natively and the data is not copied to Java fields limiting the memory usage.

One option for optimization is loading the ImageData through native code, but this actually triples the amount of memory used and copied around. The image data gets created first on the native code and then gets copied to Java and copied back to native to create the native image. As a result, this is not an option used by the SWT/eSWT implementations at least for now.