Wednesday, February 13, 2008

Consider the Source

It has been told to me many times. "Don't believe everything you read." Sometimes I still believe stuff that I simply should not. For instance, I've been trying to figure out why the javax.print.attribute.standard.MediaSize.findMedia() method starts doing strange stuff after my application has been running. According to the documentation for findMedia(), it tries to find the best match of the "standard" media sizes:
The specified dimensions are used to locate a matching MediaSize instance from amongst all the standard MediaSize instances. If there is no exact match, the closest match is used.

Indeed it seems to work when I try it, so I accept what I've read, until someone complains that the application starts failing to find the right media size. It seems that the definition of "standard MediaSize instances" changes after the application has been running for a while. I solve this by changing my code not to rely on MediaSize.findMedia(), and I'm happy that the bug is fixed, but what was really going on to cause the problem?

Fortunately, Sun has always (or least as far as I can remember) released source code for the standard library of Java, and I as a Java developer of course have a copy of their source code installed on my system, so I can take a look at what my call to MediaSize.findMedia() is really doing. The findMedia(float x, float y, int units) simply loops through a list of MediaSize entries, and looks for the one that is closest to the given dimensions. It then returns the "name" of the closest fit. Where this contradictions my assumptions is that the definition of "standard MediaSize instances" is the entire set of MediaSize instances EVER INSTANTIATED! This means that every time I call new MediaSize(x,y,units), I'm adding a new entry to the "standard" set of instances, and those do not have names on them, so findMedia(), which returns the name of the closest match, which start returning null, the name of one of my instances. Okay, now I know why my code was failing, but after looking at the code a bit more, I see a couple curious things. First I notice that the code was written by former C programmers because of the style. Then I notice that it's unnecessarily using some local variables of type double when it just needs float. Neither of these two things matter, but I notice such things.

However, when I think about things a little more, I realize that the "standard" list of media sizes is a java.util.Vector that gets an entry for every instance of MediaSize ever made. This list is never, ever cleared, and that means it's a memory leak, and one that is encountered every time the users of the site do a particular task. It is a good thing that memory is cheap and that I do not create these things in a loop that would allocate a lot of them that never get garbage collected. It does mean that I need to remove all calls to instantiate MediaSize objects as part of a user initiated action.

At least I feel I can can trust the source code.

No comments: