JS Ext

Monday, May 5, 2014

Static methods for all....and (another) reason to not use them

When I switched to my current team, I was surprised to find an endless supply of static methods and variables.  It seemed like the team really liked them.  I can understand why.  Most of the team were younger and weren't really used to design patterns and object orientation.  For them, the only reason to extend and object is to make it convenient to call common methods.  Being new to the team, I didn't try to force a paradigm shift.  I brought it up a handful of times, but everyone seemed to like their static methods.

Recently, however, I was tasked to fixing a recurring issue.  Inside of our Android app, some of our static variables were being reset to null.  It seemed like it happened when the app crashed, so we put in code to reinitialize the static variables in the Activity that gets called when the app crashes.  We were still getting sporadic null values.

Then a major problem occurred.  We started using a 3rd party Android library that was returning null values.  I disassembled the code and the developer had used static variables to store some values.  Sound familiar?  At first it happened when the app crashed, but then we noticed it happening when we ran out of memory.  The screenshot library has a memory leak....ugh!  We plugged the memory leak and the nulls in the 3rd party library went away.  The incident got me thinking.

I started doing some research on the topic.  I found lots of places talking about Android memory management.  There seemed to be a debate of where to put long-lived objects.  Some (including Google) recommended using a static variable to create a singleton.  Others suggested keeping a reference to it from the Application class.  I then found more details on what we think is going on.

First, a few things that you might not realize.  Java classes are loaded into memory.  If nobody is using a Java class, then that class can be unloaded from memory.  If someone decides to use that class again, then the class can be reloaded into memory.  This type of thing might happen if you run out of memory.

Apparently, one of the differences between a JVM and Dalvik is the definition of a "class being used", or when is it OK to unload a class.  It looks like the JVM looks for references to the class while Dalvik looks for references to an instance of the class.  It turns out that it is a very important distinction.  In the above examples, the entire class was static.  All the methods and variables were static.  There was no instance of the class.  There wasn't a need for one since everything was static.  This works in the JVM world, but it doesn't work in Dalvik.  When you are low on heap space, Dalvik will unload the static class, since by it's definition, nobody is using the class.  Then, someone calls a static method which reloads the class, reinitializing the static variables, usually to null.

I made the decision that we shouldn't use completely static classes any more.  While it is generally bad practice to use static only classes, I had a concrete technical reason to stop using them.  I rewrote the code to use instances of the classes that are referenced from the Application class.  Anyone that wants to call them needs a Context.  Luckily almost all of our code already had a reference to a Context.  We haven't had an issue since I did the refactoring.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.