ResultSet and Statement Objects
JDBC ResultSet and Statement objects will be closed when the connection that created them is closed. However, while using pooled connections, if close() is invoked on the connection, the connection will be returned to the connection pool rather than being closed. Consequently, the ResultSet and Statement objects created by the connection will not be closed automatically, and are a potential cause of memory leaks.
Explicitly close all ResultSet and Statement objects created using pooled connections. It is also a good practice to explicitly close ResultSet and Statement objects as this will release any resources held by these objects.
A Java collection holds references to other objects. It grows as elements are added to it. While the collection itself has a longer lifetime, individual elements within it do not. Hence, if the individual collection elements are not removed, the collection can grow indefinitely, and the JVM could run out of memory. Also known as Lapsed listeners since they are most commonly observed in event listeners held in collections.
Explicitly remove objects from collections if they will not be used anymore. Weak references may also solve the problem in some cases. Using weak references to plug Java memory leaks is discussed in : Java theory and practice: Plugging memory leaks with weak references. An example of using the WeakHashMap is also provided in the article.
Static classes and singletons
Static variables and classes, once loaded, will exist through out the lifetime of the application. The same is the case with Singleton objects. If there are too many singletons/static classes in the application, the available memory in the JVM will be significantly decreased for the rest of the application's lifetime. In this case it is the classloader that becomes too large. The proliferation of singletons antipattern addresses this specific issue. A similar problem is incorrect scoping. If you have an variable that might only be needed within a single method as a member variable of a class, then the variable effectively has the same lifetime as the class.
Avoid creating too many singletons. Too many is a relative term and is dependent on your application requirements and memory availability.
Data stored in the HttpSession will be available till the user logs out. Storing too much data in the HttpSession will quickly lead to OutOfMemoryError. Another problem is when persistent session are used, then the servlet may need to serialize/deserialize the objects stored in the session and this adds a significant overhead in case of large objects.
Use HttpRequest to transfer data whenever possible instead of HttpSession. If the objects have to be available for longer time, then they can be moved to the business layer. Elements in the session must be explicitly removed Java memory leaks -- Catch me if you can
Caching can play a significant part in Java memory leaks. It is similar to HttpSession usage, but outside the scope the Web tier. Too little caching will not give the expected performance boost, while too much caching may hamper performance by taking up a lot of memory.
There are a lot of sophisticated caching frameworks available (open source and commercial) which handle the memory efficiently. These frameworks come to use if you have an application that is heavily dependent on caching. A cheaper way of caching would be to use soft references, they are more suited for simpler caching requirements.
To summarize, the following is quick list of the sources of memory leaks in Java applications:
- ResultSet and Statement Objects
- Static classes and singletons
- Incorrect Scoping
How Do You Plug Java Memory Leaks?
Plug memory leaks in enterprise Java applications
Java theory and practice: Plugging memory leaks with soft references