I’d like to introduce you to a little piece of code. If, as an experienced developer, you’ve had an interview with me, the chances are you’ve been asked to evaluate this piece of code in one form or another:
final Connection con = DriverManager.getConnection(conectionString);
final Statement stmt = con.createStatement();
final ResultSet rs = stmt.executeQuery(“…”);
System.out.println(rs.getString(“id”) + “: “ + rs.getString(“message”));
Assuming nothing goes wrong, this piece of code is just fine. However, if there is an exception there is a resource leak.
In 2000 I worked on my first commercial project, a Windows desktop application. There was a certain amount of graphical manipulation and every so often the application would grind to a halt and and then eventually crash. A few people I spoke to suggested that there might be a resource leak. I was fresh out of university and I couldn’t believe that C++ for Win32 wouldn’t clean-up after itself. How wrong was I? It was a resource leak. After I got a handle to and used a Win32 resource, I wasn’t releasing it. As soon as I wrote a guard class to manage and automatically release the resource the problem went away.
I’ve been fanatical about memory and resource leaks ever since.
In 2013 I worked on a Java project with a large number of integration tests which executed a few scripts against the test database once each for many tests. All the tests ran just fine individually in my IDE, but sometimes when running all the tests at the command line, it would just hang. I don’t remember how I worked it out, but I realised I was running out of database connections as upping the maximum number available to the tests fixed the problem. Every time I encountered the problem I upped the number of connections in the pool. This of course can only go so far and I was very uncomfortable about it as I didn’t understand why the connections weren’t being released after the tests.
I’m using the same piece of boilerplate Java test code in a current project and a couple of times the problem came back. Then I reached the limit of the number of connections I could create in the pool, so I had to find the leak. This time it didn’t take too long and the problem was here:
catch (SQLException e)
Calling getConnection on the data source returns an unmanaged connection object. As you would expect, executeSqlScript doesn’t and doesn’t expect to have to manage the connection, so every time it executed a sql script it got a connection from the pool and never put it back. No wonder, when this piece of code is being run a few hundred times it was running out of connections and just hanging.
As I said, I’ve been fanatical about resource management since my early professional career, but even I get caught out sometimes. This was one of those times and it reminds me not to give other developers such a hard time for obvious mistakes.
Words: Paul Grenyer