Design-Based Leaks (Continued…)Filed Under: Weekly Tuesday Dose of goodness
Hi all,
Today I’m going to continue on the topic of design-based leaks or also known as Legal Leaks.
Design-based leaks will eventually be a better name because 99% of these leaks are due to design flaws or insufficient design and condition coverage that leads to objects being orphanated without having anyone to remove it from memory.
I’ve also mentioned in my previous article that dynamic data structures are the most susceptible to design-based leaks. However, does that mean that fixed-sized data structures are spared?
The answer is - NO! Wanna know why? Read on…
One of the most common forms of design-based leaks occurred not in C/C++ applications, but instead it occured in a language that most of us would never have guessed it - Java! Most explicitly, J2EE.
How is that so?
In J2EE, one of the most common problems is with the database APIs, namely the Connection, PreparedStatement and ResultSet interfaces.
The most commonly reported error - Connection Refused.
Why? The simplest and most direct reason would be, Connection retreived but was not closed.
So let’s a few questions here:
1) Why is there a need to close?
2) Why can’t Java’s garbage collector take care of it?
3) Is Connection Refused an effect of a memory leak?
Let’s go through 1 by 1.
1) There’s a need to close because Connection is an interface, not an explicit class and that the implementation (ie, MySQL, Oracle, etc) might have other closure procedures within their own overriden close method.
2) Java doesn’t have destructors - making auto-destruction impossible. The GC merely cleans up the memory used by the class itself; it doesn’t auto-close all the open/close items. Note: This includes BufferedReaders/Writers, OS Handles, Streams, and of course Connection objects.
3) Connection Refused is caused when the Connection pool is full. This pool is nothing but an ArrayList at best. (ArrayList is a data structure with a limited size and cannot grow). Doing it this way ensures that the database driver can never have a few thousand Connections open at a time. In short, Connection Refused is a merciful kind of exception as compared to the more generic OutOfMemory exception should drivers use dynamic data structures.
Fortunately, the interface is still fairly well designed to save itself from becoming a complete mystery. With a single point of closure (ie, .close() ) , it makes it easy for data flow analysis tools to detect non-compilance to the standards or paths that might lead to connections not being closed.
So, there’s still hope if good tools such as Jtest from Parasoft is being used, though I’ll empathize with other Java developers who have to go through a few hundred KLOCs and a few million logical paths to look for this needle in a haystack.
So did the authors of Java screw up when they decided that a destructor is not required? I’ll leave it up to you to decide.
As for the game development guys out there, don’t be too smug just because you’re not using dynamic data structures. I know there’re some guys out there who prided themselves for avoiding normal memory leaks completely by using arrays.
There’re also some guys, especially those who are doing console games, are usually constrained to a limited amount of memory. This might be something for you to look out as well.
I’ll reiterate the things to bear in mind when you’re designing your code modules:
1) Decide which data structure to use based on their usage. I know it doesn’t have anything to do with design-based leaks directly, but it will.
2) Have a flow/state chart of your module. Identify design flaws early.
3) Don’t be afraid to admit to your design flaws; admit it early and be a hero, admit it late and become zero.
4) Place comments in your codes to accurately reflect your design.
5) Be transparent and open about your work. If it’s good, it’s good. If it’s bad, seek to improve.
6) If you’re using Arrays, ensure that they’re full for the right reason.
7) If you’re using dynamic data structures, based on the design, always set a tentative limit on them. Should they exceed this limit, your application should sound the alarm. This will alert you to any possible design-based leaks.
A simple check such as - (based on StridesLib’s collection library)
if( list.getSize() > 1000)
{
//do something, throw exception or log to a file
}
If it’s done on module-basis, then the amount of work will be trivial compared to the amount of debugging you’ll most likely have to do during the later stages of development.
Conclusion
Again, it has been quite a mouthful. Do post comments to correct me if you think that I’m wrong in my understanding for Java.
Design-based leaks are silent killers that can easily and silently bring an otherwise perfect application to its knees gradually and painfully as well.
Most tools in the market, if not all, will not be able to detect such problems. Why am I so sure? The reason is simple. No tools are made to understand your application logic. Therefore, I’m very sure that these tools will not be able to pinpoint all the Design-Based Leaks directly even should they find any.
Thanks for your time reading once more, signing off!
Regards,
Jeremy
- Permalink
- Admin
- 15 Dec 2009 2:59 PM
- Comments (1)
June 26th, 2010 at 10:53 am
[...] Design-based leaks (continued) Legal Leaks [...]