In this article, I have tried to analyze the various causes which may lead to Memory Exception.
Once an ‘OutOfMemoryException’ is thrown, how best can it be handled has been discussed in this artilce.
OutOfMemoryException is thrown when there is not sufficient available memory to carry out a requested activity. In this article, I have tried to illustrate the different methods by which memory leaks can be handled in Web Applications.
When a program is loaded into memory, it is organized into three areas of memory, called segments: the text segment, stack segment, and heap segment. The text segment (sometimes also called the code segment) is where the compiled code of the program itself resides. This is the machine language representation of the program steps to be carried out, including all functions making up the program, both user defined and system.
The remaining two areas of system memory are where storage may be allocated by the compiler for data storage. The stack is where memory is allocated for automatic variables within functions. A stack is a Last In First Out (LIFO) storage device where new storage is allocated and deallocated at only one “end”, called the top of the stack.
When a program begins executing in the function main(), space is allocated on the stack for all variables declared within main(). If main() calls a function, func(), additional storage is allocated for the variables in func() at the top of the stack. It should be clear that memory allocated in this area will contain garbage values left over from previous usage.
The heap segment provides more stable storage of data for a program; memory allocated in the heap remains in existence for the duration of a program. Therefore, global variables (storage class external), and static variables are allocated on the heap. The memory allocated in the heap area, if initialized to zero at program start, remains zero until the program makes use of it. Thus, the heap area need not contain garbage.
Once an OutOfMemoryException has been thrown, the following checks should be carried out:
Handling Connection Objects: Check whether all objects pertaining to Connection, ResultSet, Statement and PreparedStatement have been properly closed in the finally block. Since the Connection objects are drawn from a Connection pool (the pool size depends on Server Configuration), if multiple Connection objects are created without closing them, it would result in reduction of the connection pool size and may throw an OutOfMemoryException if the pool is exhausted. Hence, even though there might be unused connection objects, the pool may be exhausted resulting in exception being thrown.
Handling OutputStream Objects: Check whether all OutputStream objects have been properly closed in the finally block. Streams are usually resource intensive objects and thus should be handled in a point-to-point manner. Hence it is imperative to close the streams individually to prevent memory leaks.
Checking for Static Variables: Static variables are stored in the heap and only one instance of variable is available throughout the lifetime of the application. Since static variables are not garbage collected till the class is unloaded or the variables are explicitly set to NULL, it needs to be checked whether all static variables are being used or some are unnecessarily occupying heap space.
Checking Third Party APIs: It is necessary to check the memory utilization of third party APIs. If the memory utilization is high (for example, if many static variables have been used), it may lead to OutOfMemoryException.
Usage of Singleton Classes: Adoption of the Singleton pattern results in creation of classes for which memory is allocated on the heap and not freed anywhere which may result in memory leaks. Hence, it is necessary to check the design pattern being followed, and in case of singleton pattern, check the number of classes which may be holding up space in the heap. Singleton pattern should not be used unless imperative.
Size of Session Objects: Since, it is possible to put large objects in a session, it is necessary to check the session size. Hence, it is important to check during memory leaks, the size of the session as well as the objects that might have been put in the session. To avoid memory leaks, only those objects should be put in the session which need to be put and should be removed when not required anymore.
If the above suggested checks do not throw a cause for memory leaks, the below mentioned methods may be carried out to determine the cause for memory leaks:
Using verbose:gc: The verbose:gc utility can be configured in startWebLogic.cmd to obtain information about the Java Object Heap in real time while running the Java application.
To activate the utility, Java must be run with -verbose:gc option.
For using verbose:gc; set the JVM size to 64 MB so that we may reach the maximum without load on the server. If the used memory does not drop to initial levels after full GC, then it would indicate a memory leak. This is a raw mechanism of analyzing in the absence of a profiling tool.
The following piece of code can also be used to track the amount of free memory, available memory and utilized memory.
long heapSize = Runtime.getRuntime().totalMemory();long heapMaxSize = Runtime.getRuntime().maxMemory();long heapFreeSize = Runtime.getRuntime().freeMemory();Log.logInfo("LeakAction", "perform", "heapSize in MB : " + heapSize / 1000000); Log.logInfo("LeakAction", "perform", "heapMaxSize: in MB" + heapMaxSize / 1000000);Log.logInfo("LeakAction", "perform", "heapFreeSizeheapFreeSize: in MB " + heapFreeSize / 1000000);
Considering the usage of Struts 1.1 Framework, the above code needs to be placed in the action class for the corresponding JSP just before method ‘perform’ returns the ActionForward.
Using JProbe with LoadRunner: JProbe is an enterprise-class Java profiler providing intelligent diagnostics on memory usage, performance and test coverage, allowing developers to quickly pinpoint the root cause of application code performance and stability problems that obstruct component and integration integrity. LoadRunner is a performance and load testing product by HP and can be used with JProbe to pinpoint the cause for memory leaks.
Eclipse Test & Performance Tools Platform:
The Eclipse Test and Performance Tools Platform (TPTP) Project provides an open platform supplying powerful frameworks and services that allow software developers to build unique test and performance tool, both open source and commercial, that can be easily integrated with the platform and with other tools.
TPTP addresses the entire test and performance life cycle, from early testing to production application monitoring, including test editing and execution, monitoring, tracing and profiling, and log analysis capabilities.
CodePro Profiler™ is an Eclipse-based software development product that enables Java developers to efficiently identify performance issues early in the development cycle. Use CodePro Profiler during development to efficiently locate performance bottlenecks, pin down memory leaks and resolve threading issues in a painless and intuitive manner
Focus on creating business logic, rather than on tedious manual instrumentation of debugging code to identify performance problems. CodePro Profiler is the first enterprise-ready performance analysis tool that is designed specifically for Eclipse development platforms to ensure creation of fast, reliable and high quality applications.
VisualVM is a visual tool integrating several commandline JDK tools and lightweight profiling capabilities. Designed for both production and development time use, it further enhances the capability of monitoring and performance analysis for the Java SE platform.