Showing posts with label Memory Analysis. Show all posts
Showing posts with label Memory Analysis. Show all posts

Apr 26, 2010

Garbage Collection and Heap Memory Management with Java

This article has been prepared to understand the process of Garbage Collection. This includes how the JVM carry out the memory reclaim process from heap. This document also covers the JVM and Tomcat server settings and precautions need to take while coding which we can use to use the better heap memory.

Overview:

Mostly the programmers especially java people think that they are not at all required to worry about the internal memory allocation and freeing that memory. It is simply assumed that create the objects, use it and java will take care of the removing or freeing the allocated memory through the mechanism like Garbage Collection. Due to this it is assumed that Java has resolved one of the nasty problems that plague other programming languages—the dreaded memory leak. But the question is “Is it true?”

Enterprise applications written in the Java language involve complex object relationships and utilize large numbers of objects. Although, the Java language automatically manages memory associated with object life cycles, understanding the application usage patterns for objects is important. In particular, verify the following:


  • The application is not over-utilizing objects.
  • The application is not leaking objects.
  • The Java heap parameters are set properly to handle a given object usage pattern.

Understanding the effect of garbage collection is necessary to apply these management techniques

.

Garbage Collection

The garbage collector first performs a task called marking. The garbage collector traverses the application graph, starting with the root objects; those are objects that are represented by all active stack frames and all the static variables loaded into the system. Each object the garbage collector meets is marked as being used, and will not be deleted in the sweeping stage.

The sweeping stage is where the deletion of objects takes place. There are many ways to delete an object: The traditional C way was to mark the space as free, and let the allocator methods use complex data structures to search the memory for the required free space. This was later improved by providing a defragmenting system which compacted memory by moving objects closer to each other, removing any fragments of free space and therefore allowing allocation to be much faster:


clip_image002

For the last trick to be possible a new idea was introduced in garbage collected languages: even though objects are represented by references, much like in C, they don’t really reference their real memory location. Instead, they refer to a location in a dictionary which keeps track of where the object is at any moment.

Fortunately for us - but unfortunately for these garbage collection algorithms - our servers and personal computers got faster (and multiple) processors and bigger memory capacities. Compacting memory areas this large often was very taxing on the application, especially considering that when doing that, the whole application had to freeze due to the changes in the virtual memory map. Fortunately for us though, some smart people improved those algorithms in three ways: concurrency, parallelization and generational collection.


Garbage Collection Algorithms

There are around six basic garbage collection strategies with JDK 1.4.2 version and more that dozens of command line options for tuning and configuring it. The use of all the garbage collection algorithms are same that is to identify the memory blocks that are not reachable by the user programs resulting in the OutOfMemory issues. Below are the algorithms that are used for garbage collection.

1 – Reference Counting:

Each object has an associated reference count. This count indicates the number of active references to that object. If this count is zero, it is garbage and can be recycled. Whenever the reference is modified, the count is updated. Once this count is zero, the memory is reclaimed.

2 – Tracing Collectors:

Mostly the standard garbage collectors do not use Reference Counting. They will use some form of tracing collector’s algorithms. This algorithm will trace all objects starting from root until all reachable objects have been examined.

3 – Mark-Sweep collectors:

This is most basic form of collector algorithm. In this case the collector visits each node starting from root and marks each node. Once there are no any references, the collection is complete. The heap is swept and the objects not marked are reclaimed and returned to free list.

4 – Copying Collectors:

In this case, the heap is divided into equally sized semi spaces. One with active data and another with unused. Once the active space fills up, the objects are copied from active to unused space and the roles are flipped becoming unused space as active. This has advantages as it examines only active data. But will have a overhead of copying data from active to unused space.

5 – Heap Compaction:

In the copying collectors, the set of live objects can be compacted at the bottom of heap. This improves locality of reference and eliminates heap fragmentation and greatly reduces the cost of object allocation which eliminates the need to maintain free lists or look-aside lists or perform best-fit or first-fit algorithms and allocating N bytes is simple to add N to heal pointer.

6 – Mark-compact collectors:

The copying algorithm has excellent performance characteristics, but it has the drawback of requiring twice as much memory as a mark-sweep collector. The mark-compact algorithm combines mark-sweep and copying in a way that avoids this problem, at the cost of some increased collection complexity. Like mark-sweep, mark-compact is a two-phase process, where each live object is visited and marked in the marking phase. Then, marked objects are copied such that all the live objects are compacted at the bottom of the heap. If a complete compaction is performed at every collection, the resulting heap is similar to the result of a copying collector -- there is a clear demarcation between the active portion of the heap and the free area, so that allocation costs are comparable to a copying collector. Long-lived objects tend to accumulate at the bottom of the heap, so they are not copied repeatedly as they are in a copying collector.

JDK uses all of the algorithms in some sense. Early JDK used mark-sweep and mark-compact while version 1.2 and later employed a hybrid approach called generational approach. In this the heap is divided into multiple generations. Objects are created in young generation and the objects that meet some criteria are promoted to older generation. It can use different collection strategy for different generations separately.

By default, the 1.4.1 JDK divides the heap into two sections, a young generation and an old generation. (Actually, there is also a third section, the permanent space, which is used for storing loaded class and method objects.) The young generation is divided into a creation space, often called Eden, and two survivor semi-spaces, using a copying collector.

Reasons for OutOfMemoryError errors

1. You are out of memory. Add more to your heap.

2. You are out of memory. The code is hanging on to object references and a GC can’t do the job. Use the profiler to debug this code.

3. You ran out of file descriptors. This can happen if the threshold is too low.

4. You have too many threads running. Some OS have limits to the number of threads which may be executed by the process. Refer to your OS docs to raise this threshold.

5. If you have a lot of servlets or JSPs, you may need to increase your permanent generation. By default it is 64M. Quadrupling it to be –XX:maxPermSize=256m can be good start.

6. Your OS limits the amount of memory your process may take.

7. The JVM has a bug. This has been known to happen with JVM1.2 and using EJBs with another servlet engine.

8. On the platform look for the java –X options. This may be very helpful.


Garbage Collection Tips and Memory Leaks in Coding Context

1 Small Objects:

Small objects are easy to allocate while large objects will be allocated directly in old generation heap area, take long to initialize and might cause fragmentation. It is always better to allocate small immutable objects. The mutable objects will eventually make your code more obscure at best, or fragment the memory and confuse GC at worst.

2 Non Uniformed Memory Access:

Keep your objects constrained to single thread as much as possible. This will increase the memory usage performance. The basic idea of Non Uniformed Memory Access is to provide increased performance for processors by allowing each processor to work with specific memory space.

3 Object Pools:

Allocation of majority of objects is faster. So there is no any need to have pools for objects as they create issues except for the reasons like creation and initialization of objects are more expensive like connections. The issues are like an unused object takes memory for no reason. Also synchronization is required to fetch an object which is slow process.

4 Finalizable Object:

When a finalizable object is allocated it is marked as such. When the application has no more references to it, the GC enqueue it in the object finalization queue. The JVM has a thread dedicated to removing elements from this queue and calling the finalize method on them; however, to keep the data integrity on the object, the GC does not claim it and traverses its tree as a live object! Only after the object’s finalize method gets called, the object and the references it contains are allowed to be claimed.

Memory

Leaks:
  • While the GC does a great job at removing unreachable objects, it doesn’t help against memory leaks as they might occur by sloppy code which leaves references to unused objects. The following list contains the common trouble-makers and some solutions:
  • Objects defined in higher scope than they should might stay will stay alive longer than expected. Always define the objects in the lowest scope possible for them.
  • Listeners for Observable objects which were not removed after their task was done will stay alive, receive events and spend processor and memory resources for no reason. Always make sure the listeners are removed from their Observable class when they are not needed anymore.
  • Always use the finally clause when removing references to listeners or other type of objects from usually persistent collections.
  • Instances of inner class contain references to their outer classes. You must be aware of this behavior and if you don’t use the outer class, define the inner class as static.
  • Using Maps, the kept object usually should remove themselves from the Map when their use is over which is often forgotten. Luckily WeakHashMap keeps the keys as weak references and should be used for such metadata.
  • And the use of finalize() method which might be extremely slow and delay the claiming of new memory spaces or even do worse and resurrect the finalize object.
  • If the Collection objects are used to store user defined objects, set the reference to null (for the root object) once you have finished with. This way the total memory will be available for garbage collection.

Tomcat Server Settings for Heap Usage

We can reset the heap memory size which is used by Tomcat server. This is achieved by setting the environmental variable CATALINA_OPTS in startup.sh. Below are the environmental variables which can be set to have max and min limit for heap memory usage by Tomcat and JVM.

1 - CATALINA_OPTS

This variable is used to set minimum and maximum heap memory that Tomcat uses. This variable is set in startup.sh for Linux and in startup.bat for Windows platforms. Below is the syntax for both

For Windows -

Set CATALINA_OPTS=”-Xms256m –Xmx1024m”

For UNIX –

export CATALINA_OPTS=”-Xms256m –Xmx1024m”

2 – JAVA_OPTS

This variable is used to set minimum and maximum heap memory that JVM uses. This is also set in startup.sh for Linux and startup.bat for Windows platforms. Below is the syntax to set in both environments

For Windows –

Set JAVA_OPTS=”-Xms256m –Xmx1024m”

For UNIX –

Export JAVA_OPTS=”-Xms256m –Xmx1024m”

In both of these settings –Xms indicates the minimum heap size Tomcat or JVM will use. And –Xmx indicates the maximum heap size that will be used. The setting of these parameters will also decide the garbage collection cycles. So this minimum and maximum number should be set accordingly. Also if the maximum limit is much more, it may happen that GC will take long to check the unreachable objects which will again cause the memory issues. So we should be cautious while setting the minimum and maximum limits.

Memory profiling Tools

There are various tools available which can carry out the profiling of memory used by java programs. Heap profiling provides the information about memory allocation footprints of the application. We can do following tasks through these tools –
  • Observer Garbage Collection cycles
  • Can observer memory utilizations
  • Can observer CPU utilizations
  • Can check the Object references

Some of the tools and utilities like jmap, jhat, NetBean’s profiler, JProbe etc can be used for such purposes. These can read the heap dump files also and can provide you the visual representations. This is the tool which can do all above functions and can provide many charts that will help developer to analyze the memory related issues in java code. Below is the graph that may be seen in JProbe.


clip_image004

The JProbe Memory Debugger allows developers to observe and record how an application is using memory as it runs. This, as with the Profiler, was surprisingly fast considering the overhead that is surely involved. A graph records memory usage (not unlike the Performance Monitor in Windows) at regular intervals that are user selectectable. Additionally, the Memory Leak Doctor will allow developers to take a more granular look at what is going on inside the application and help to identify the key causes.

Conclusion

By looking at the tips given above the developers can avoid the issues related to memory. Also the developers can make use of the available profiling tools which are helpful in identifying the memory leaks and improve the performance.


Garbage Collection and Heap Memory Management with Java

This article has been prepared to understand the process of Garbage Collection. This includes how the JVM carry out the memory reclaim process from heap. This document also covers the JVM and Tomcat server settings and precautions need to take while coding which we can use to use the better heap memory.

Overview:

Mostly the programmers especially java people think that they are not at all required to worry about the internal memory allocation and freeing that memory. It is simply assumed that create the objects, use it and java will take care of the removing or freeing the allocated memory through the mechanism like Garbage Collection. Due to this it is assumed that Java has resolved one of the nasty problems that plague other programming languages—the dreaded memory leak. But the question is “Is it true?”

Enterprise applications written in the Java language involve complex object relationships and utilize large numbers of objects. Although, the Java language automatically manages memory associated with object life cycles, understanding the application usage patterns for objects is important. In particular, verify the following:


  • The application is not over-utilizing objects.
  • The application is not leaking objects.
  • The Java heap parameters are set properly to handle a given object usage pattern.

Understanding the effect of garbage collection is necessary to apply these management techniques

.

Garbage Collection

The garbage collector first performs a task called marking. The garbage collector traverses the application graph, starting with the root objects; those are objects that are represented by all active stack frames and all the static variables loaded into the system. Each object the garbage collector meets is marked as being used, and will not be deleted in the sweeping stage.

The sweeping stage is where the deletion of objects takes place. There are many ways to delete an object: The traditional C way was to mark the space as free, and let the allocator methods use complex data structures to search the memory for the required free space. This was later improved by providing a defragmenting system which compacted memory by moving objects closer to each other, removing any fragments of free space and therefore allowing allocation to be much faster:


clip_image002

For the last trick to be possible a new idea was introduced in garbage collected languages: even though objects are represented by references, much like in C, they don’t really reference their real memory location. Instead, they refer to a location in a dictionary which keeps track of where the object is at any moment.

Fortunately for us - but unfortunately for these garbage collection algorithms - our servers and personal computers got faster (and multiple) processors and bigger memory capacities. Compacting memory areas this large often was very taxing on the application, especially considering that when doing that, the whole application had to freeze due to the changes in the virtual memory map. Fortunately for us though, some smart people improved those algorithms in three ways: concurrency, parallelization and generational collection.


Garbage Collection Algorithms

There are around six basic garbage collection strategies with JDK 1.4.2 version and more that dozens of command line options for tuning and configuring it. The use of all the garbage collection algorithms are same that is to identify the memory blocks that are not reachable by the user programs resulting in the OutOfMemory issues. Below are the algorithms that are used for garbage collection.

1 – Reference Counting:

Each object has an associated reference count. This count indicates the number of active references to that object. If this count is zero, it is garbage and can be recycled. Whenever the reference is modified, the count is updated. Once this count is zero, the memory is reclaimed.

2 – Tracing Collectors:

Mostly the standard garbage collectors do not use Reference Counting. They will use some form of tracing collector’s algorithms. This algorithm will trace all objects starting from root until all reachable objects have been examined.

3 – Mark-Sweep collectors:

This is most basic form of collector algorithm. In this case the collector visits each node starting from root and marks each node. Once there are no any references, the collection is complete. The heap is swept and the objects not marked are reclaimed and returned to free list.

4 – Copying Collectors:

In this case, the heap is divided into equally sized semi spaces. One with active data and another with unused. Once the active space fills up, the objects are copied from active to unused space and the roles are flipped becoming unused space as active. This has advantages as it examines only active data. But will have a overhead of copying data from active to unused space.

5 – Heap Compaction:

In the copying collectors, the set of live objects can be compacted at the bottom of heap. This improves locality of reference and eliminates heap fragmentation and greatly reduces the cost of object allocation which eliminates the need to maintain free lists or look-aside lists or perform best-fit or first-fit algorithms and allocating N bytes is simple to add N to heal pointer.

6 – Mark-compact collectors:

The copying algorithm has excellent performance characteristics, but it has the drawback of requiring twice as much memory as a mark-sweep collector. The mark-compact algorithm combines mark-sweep and copying in a way that avoids this problem, at the cost of some increased collection complexity. Like mark-sweep, mark-compact is a two-phase process, where each live object is visited and marked in the marking phase. Then, marked objects are copied such that all the live objects are compacted at the bottom of the heap. If a complete compaction is performed at every collection, the resulting heap is similar to the result of a copying collector -- there is a clear demarcation between the active portion of the heap and the free area, so that allocation costs are comparable to a copying collector. Long-lived objects tend to accumulate at the bottom of the heap, so they are not copied repeatedly as they are in a copying collector.

JDK uses all of the algorithms in some sense. Early JDK used mark-sweep and mark-compact while version 1.2 and later employed a hybrid approach called generational approach. In this the heap is divided into multiple generations. Objects are created in young generation and the objects that meet some criteria are promoted to older generation. It can use different collection strategy for different generations separately.

By default, the 1.4.1 JDK divides the heap into two sections, a young generation and an old generation. (Actually, there is also a third section, the permanent space, which is used for storing loaded class and method objects.) The young generation is divided into a creation space, often called Eden, and two survivor semi-spaces, using a copying collector.

Reasons for OutOfMemoryError errors

1. You are out of memory. Add more to your heap.

2. You are out of memory. The code is hanging on to object references and a GC can’t do the job. Use the profiler to debug this code.

3. You ran out of file descriptors. This can happen if the threshold is too low.

4. You have too many threads running. Some OS have limits to the number of threads which may be executed by the process. Refer to your OS docs to raise this threshold.

5. If you have a lot of servlets or JSPs, you may need to increase your permanent generation. By default it is 64M. Quadrupling it to be –XX:maxPermSize=256m can be good start.

6. Your OS limits the amount of memory your process may take.

7. The JVM has a bug. This has been known to happen with JVM1.2 and using EJBs with another servlet engine.

8. On the platform look for the java –X options. This may be very helpful.


Garbage Collection Tips and Memory Leaks in Coding Context

1 Small Objects:

Small objects are easy to allocate while large objects will be allocated directly in old generation heap area, take long to initialize and might cause fragmentation. It is always better to allocate small immutable objects. The mutable objects will eventually make your code more obscure at best, or fragment the memory and confuse GC at worst.

2 Non Uniformed Memory Access:

Keep your objects constrained to single thread as much as possible. This will increase the memory usage performance. The basic idea of Non Uniformed Memory Access is to provide increased performance for processors by allowing each processor to work with specific memory space.

3 Object Pools:

Allocation of majority of objects is faster. So there is no any need to have pools for objects as they create issues except for the reasons like creation and initialization of objects are more expensive like connections. The issues are like an unused object takes memory for no reason. Also synchronization is required to fetch an object which is slow process.

4 Finalizable Object:

When a finalizable object is allocated it is marked as such. When the application has no more references to it, the GC enqueue it in the object finalization queue. The JVM has a thread dedicated to removing elements from this queue and calling the finalize method on them; however, to keep the data integrity on the object, the GC does not claim it and traverses its tree as a live object! Only after the object’s finalize method gets called, the object and the references it contains are allowed to be claimed.

Memory

Leaks:
  • While the GC does a great job at removing unreachable objects, it doesn’t help against memory leaks as they might occur by sloppy code which leaves references to unused objects. The following list contains the common trouble-makers and some solutions:
  • Objects defined in higher scope than they should might stay will stay alive longer than expected. Always define the objects in the lowest scope possible for them.
  • Listeners for Observable objects which were not removed after their task was done will stay alive, receive events and spend processor and memory resources for no reason. Always make sure the listeners are removed from their Observable class when they are not needed anymore.
  • Always use the finally clause when removing references to listeners or other type of objects from usually persistent collections.
  • Instances of inner class contain references to their outer classes. You must be aware of this behavior and if you don’t use the outer class, define the inner class as static.
  • Using Maps, the kept object usually should remove themselves from the Map when their use is over which is often forgotten. Luckily WeakHashMap keeps the keys as weak references and should be used for such metadata.
  • And the use of finalize() method which might be extremely slow and delay the claiming of new memory spaces or even do worse and resurrect the finalize object.
  • If the Collection objects are used to store user defined objects, set the reference to null (for the root object) once you have finished with. This way the total memory will be available for garbage collection.

Tomcat Server Settings for Heap Usage

We can reset the heap memory size which is used by Tomcat server. This is achieved by setting the environmental variable CATALINA_OPTS in startup.sh. Below are the environmental variables which can be set to have max and min limit for heap memory usage by Tomcat and JVM.

1 - CATALINA_OPTS

This variable is used to set minimum and maximum heap memory that Tomcat uses. This variable is set in startup.sh for Linux and in startup.bat for Windows platforms. Below is the syntax for both

For Windows -

Set CATALINA_OPTS=”-Xms256m –Xmx1024m”

For UNIX –

export CATALINA_OPTS=”-Xms256m –Xmx1024m”

2 – JAVA_OPTS

This variable is used to set minimum and maximum heap memory that JVM uses. This is also set in startup.sh for Linux and startup.bat for Windows platforms. Below is the syntax to set in both environments

For Windows –

Set JAVA_OPTS=”-Xms256m –Xmx1024m”

For UNIX –

Export JAVA_OPTS=”-Xms256m –Xmx1024m”

In both of these settings –Xms indicates the minimum heap size Tomcat or JVM will use. And –Xmx indicates the maximum heap size that will be used. The setting of these parameters will also decide the garbage collection cycles. So this minimum and maximum number should be set accordingly. Also if the maximum limit is much more, it may happen that GC will take long to check the unreachable objects which will again cause the memory issues. So we should be cautious while setting the minimum and maximum limits.

Memory profiling Tools

There are various tools available which can carry out the profiling of memory used by java programs. Heap profiling provides the information about memory allocation footprints of the application. We can do following tasks through these tools –
  • Observer Garbage Collection cycles
  • Can observer memory utilizations
  • Can observer CPU utilizations
  • Can check the Object references

Some of the tools and utilities like jmap, jhat, NetBean’s profiler, JProbe etc can be used for such purposes. These can read the heap dump files also and can provide you the visual representations. This is the tool which can do all above functions and can provide many charts that will help developer to analyze the memory related issues in java code. Below is the graph that may be seen in JProbe.


clip_image004

The JProbe Memory Debugger allows developers to observe and record how an application is using memory as it runs. This, as with the Profiler, was surprisingly fast considering the overhead that is surely involved. A graph records memory usage (not unlike the Performance Monitor in Windows) at regular intervals that are user selectectable. Additionally, the Memory Leak Doctor will allow developers to take a more granular look at what is going on inside the application and help to identify the key causes.

Conclusion

By looking at the tips given above the developers can avoid the issues related to memory. Also the developers can make use of the available profiling tools which are helpful in identifying the memory leaks and improve the performance.


Apr 12, 2010

Case Study on High CPU utilization by Java GUI Based Application

Case Study: Increase in CPU usage for a Multi-Thread Java Application.

Problem Description:

A multi-threaded GUI based Java application running on a Solaris machine caused a significant rise in the CPU usage leading to slowness of the application and occasional hang-ups.

The prstat output is as follows:

PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP

4313 vinay 159M 83M run 0 0 0:15:07 40% vinayview/53

4312 root 22M 19M sleep 59 0 0:02:15 5.1% mmdp/31

4484 vinay 3280K 2840K cpu0 49 0 0:00:00 0.2% prstat/1

Analysis:

  • Usually for a multi-thread GUI java application, the common problem found is the unusual increase in CPU usage and slowness. The default heap size defined for the JVM is usually not enough to run big applications since lots of objects are created and processed. If the allocated heap size is not enough, then Garbage Collector runs continuously to clear the unused objects consuming majority of CPU resource. Hence, tuning the JVM heap size becomes necessary.
  • The rule of thumb is to set same values for both minimum and maximum heap memory but it can be changed as per the requirement of the application.

Solution:

The above problem was solved by increasing the minimum and maximum heap size to 256 MB each as against the default values of 1MB and 64MB respectively. The minimum and maximum values for the heap size are passed as arguments to the VM while creating the executable for the application.

The code snippet is as follows:

// *********************************************************

// ***** IMPORTANT *****

// specify vm_args version # if you use JDK1.1.2 and beyond

// *********************************************************

vm_args.version = JNI_VERSION_1_2 ;

options[0].optionString = cpathoption;

options[1].optionString = vhomeoption;

options[2].optionString = doption;

options[3].optionString = "-Xms256m";

options[4].optionString = "-Xmx256m";

vm_args.options = options;

vm_args.ignoreUnrecognized = JNI_TRUE;

The prstat output after tuning the JVM heap size is as follows:

PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP

4328 vinay 368M 89M sleep 59 0 0:00:14 1.3% vinayview/21

1278 root 16M 13M sleep 59 0 0:43:45 0.3% mmdp/26

1410 root 170M 79M sleep 59 -20 1:10:59 0.1% java/37

4333 vinay 4896K 4552K cpu1 59 0 0:00:00 0.1% prstat/1

Even for running a java applet, the runtime parameters require to be set. Since JVM runs before the execution of the applet so the runtime parameters can be set using the Java Control Panel.

The users who have deployed the latest Jdk will get an option, Java Plug-in node which enables the option to add runtime parameters through applet tag.

References:

Case Study on High CPU utilization by Java GUI Based Application

Case Study: Increase in CPU usage for a Multi-Thread Java Application.

Problem Description:

A multi-threaded GUI based Java application running on a Solaris machine caused a significant rise in the CPU usage leading to slowness of the application and occasional hang-ups.

The prstat output is as follows:

PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP

4313 vinay 159M 83M run 0 0 0:15:07 40% vinayview/53

4312 root 22M 19M sleep 59 0 0:02:15 5.1% mmdp/31

4484 vinay 3280K 2840K cpu0 49 0 0:00:00 0.2% prstat/1

Analysis:

  • Usually for a multi-thread GUI java application, the common problem found is the unusual increase in CPU usage and slowness. The default heap size defined for the JVM is usually not enough to run big applications since lots of objects are created and processed. If the allocated heap size is not enough, then Garbage Collector runs continuously to clear the unused objects consuming majority of CPU resource. Hence, tuning the JVM heap size becomes necessary.
  • The rule of thumb is to set same values for both minimum and maximum heap memory but it can be changed as per the requirement of the application.

Solution:

The above problem was solved by increasing the minimum and maximum heap size to 256 MB each as against the default values of 1MB and 64MB respectively. The minimum and maximum values for the heap size are passed as arguments to the VM while creating the executable for the application.

The code snippet is as follows:

// *********************************************************

// ***** IMPORTANT *****

// specify vm_args version # if you use JDK1.1.2 and beyond

// *********************************************************

vm_args.version = JNI_VERSION_1_2 ;

options[0].optionString = cpathoption;

options[1].optionString = vhomeoption;

options[2].optionString = doption;

options[3].optionString = "-Xms256m";

options[4].optionString = "-Xmx256m";

vm_args.options = options;

vm_args.ignoreUnrecognized = JNI_TRUE;

The prstat output after tuning the JVM heap size is as follows:

PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP

4328 vinay 368M 89M sleep 59 0 0:00:14 1.3% vinayview/21

1278 root 16M 13M sleep 59 0 0:43:45 0.3% mmdp/26

1410 root 170M 79M sleep 59 -20 1:10:59 0.1% java/37

4333 vinay 4896K 4552K cpu1 59 0 0:00:00 0.1% prstat/1

Even for running a java applet, the runtime parameters require to be set. Since JVM runs before the execution of the applet so the runtime parameters can be set using the Java Control Panel.

The users who have deployed the latest Jdk will get an option, Java Plug-in node which enables the option to add runtime parameters through applet tag.

References:

Oct 8, 2009

A Simple Approach to Memory Analysis

Introduction

Memory Leaks are a common error in programming, especially when the language used to write the Code has no in-built automatic garbage collection mechanism. A memory leak can greatly reduce the performance of the system by reducing the amount of available memory especially when the amount of memory available in a system is very limited (in the case of portable systems and embedded applications) and when the program runs for long periods of time (such as background tasks on servers). Due to the prevalence of the memory leak bugs, a number of debugging tools such as IBM Rational Purify, Bounds Checker, memwatch etc. have been developed. Another such tool is User Mode Heap Dump (UMDH). The advantage of using UMDH is that it is very light-weight and fairly all the memory leaks in an application can be traced along with the line number in the source code where the memory has been leaked in a simple and easier way.

The UMDH utility dumps information about the heap allocations of a process and this information include:

· the ‘callstack’ for each allocation,

· the number of allocations that are made through that ‘callstack’, and

· the number of bytes that are consumed through that ‘callstack’.

The UMDH utility also helps compare two UMDH logs to provide an analysis of the difference between them. This information is actually used to check whether there is a memory leak or not.


Pre-requisites for using UMDH

Installing the UMDH Utility:

The UMDH utility is included with the Debugging Tools for Windows. It can be downloaded from the following Web site:

http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx

After installing the utility, the System PATH environment variable must be set to the location where the UMDH is installed.

clip_image002

Fig. 1: Setting the System PATH Environment Variable

The Windows Symbol Package for Windows XP must be downloaded from the Microsoft Web Site mentioned below and the path where the symbol files are installed must be added to the ‘_NT_SYMBOL_PATH’ environment variable. This has to be done to get the details of the Windows Function Calls in the Stack Trace.

The Windows Symbol package can be downloaded from the Web Site:

http://www.microsoft.com/whdc/DevTools/Debugging/symbolpkg.mspx

clip_image004

Fig. 2: Setting the ‘_NT_SYMBOL_PATH’ Environment Variable

Then, the Global Flags has to be set to enable the creation of the User Mode Stack Trace Database. This is just to let the operating system know that the kernel needs to track the memory allocations made by the application.

For example, if the heap dump is required for ‘Reg.exe’. First, the stack trace acquisition must be enabled for ‘Reg.exe’. By default, this feature is not enabled. The command to enable this feature is:

clip_image005

clip_image007

Fig. 3: Enabling the Stack Traces for ‘Reg.exe’.

Note: The command does not enable stack tracing for processes that are already running. It only enables the stack tracing for all the future executions of ‘Reg.exe’.

The flag can also be set through the ‘GFLAGS’ user interface (run Gflags.exe without any arguments in the command prompt to get the user interface).

clip_image009

Fig. 4: Enabling the Stack Traces for ‘Reg.exe’ from the GUI of ‘Gflags’ Utility.

The -ust option for ‘gflags’ can be used to disable the stack tracing when the debugging is finished.


Using UMDH

After the program is started, the Process ID (PID) of the process must be determined. The PID of the application can be obtained from the output of the ‘tlist’ application or the Task Manager.

The UMHD utility can be used now to get the information regarding the heap allocations of a process.

The Command to be used is:

clip_image010

For Example,

If the Process ID is 2204 and the Output File Name is Log01.log, the command to be given is:

clip_image011

The complete heap dump of the ‘Reg’ Process is now in the ‘Log01.log’ file. This file shows all the allocations that were made and the call stacks where the allocations were made.

The Heap Dump is obtained after each successive execution of the application or after the execution of a particular feature in the application. The subsequent executions must be equivalent. For example, if a certain procedure is followed [Triggering the events in the GUI or running a specific module in the application etc.] during the first execution of the application, the same must be followed in the subsequent execution.

The general principle of operation is that UMDH is typically run two (or more times), once to capture a “baseline” snapshot of the process after it has finished initializing (as there are expected to always be a number of outstanding allocations while the process is running that would not be normally expected to be freed until process exit time.

UMDH is then run again in a special mode that is designed to essentially do a logical “diff” between the “baseline” snapshot and the “leaked” snapshot, filtering out any allocations that were present in both of them and returning a list of new, outstanding allocations, which would generally include any leaked heap blocks. It matches the back traces from each file and calculates the increase in bytes allocated for each back trace. These are then displayed in descending order of size of leak. The first line of each backtrace output shows the size of the leak in bytes, followed by the (last-first) difference in parentheses.

The Syntax for the Comparison is:

umdh File01 File02 > File03

where File01 and File02 are the Log Files obtained in two different times the former at an earlier time and the latter at a later time. File03 is the File where the Comparison Information is to be saved.

For Example,

umdh File01.log File02.log > Comparison.log

The various options that can be used with the UMDH utility are:

-d : to display the Output in Decimal (default is Hexadecimal).

-v : To get the verbose output which includes the actual back traces as well as summary information.

-l : To get the file and line number information or the traces.

Demo:

I used a Win32 Test Application which leaks Memory after each Command Button Click. After enabling the ‘User Mode Stack Trace Database’, I started the application and its Process ID was ‘408.

I clicked the Command Button Once and executed the UMDH Tool to create a baseline snapshot of the heap allocations using the following command:

clip_image012

Then, I clicked the Command Button again and executed the UMDH Tool to create the second snapshot of the Heap Allocations. The Command used was the same as the above except that the Output File Name was changed to ‘Log02.log’.

Note: As each output File is a discrete entity, data is not appended to the end of each file. So, if a batch file is intended to run every ten minutes, we’ll have to ensure that the output file name is different for each snapshot.

After taking the two snapshots of the heap allocation, the UMDH Tool can be used to compare the two files and create an output file. The Command used was:

clip_image013

Each Log Entry in the ‘Diff.log’ has the Following Syntax:

clip_image014

One such Log Entry had the Following Data:

clip_image015

From the above Output, one can infer that Memory was leaked in the Line No. 219 in the ‘TestAppl01.cpp’ File.

The memory leaks are listed in descending order of bytes leaked; each will be followed by the complete stack trace of the allocation call. Depending on the cause, this may either pinpoint the bug / leak, or at least show a good place to set a breakpoint for debugging.

I’ve embedded the Code for the Sample Application and the Logs which were obtained.

clip_image017


Conclusion

UMDH is a fairly simple tool to use and it can very effectively used to pin-point the location of memory leak. All we need to do is to have the Symbol File ( pdb ) of the Application and the Symbol Files of the Windows DLL’s. I’ve included a very simple application as an example just to drive home the idea of using this tool. This tool even can be used to find memory leaks in an application which has a very large code base.


References

1. http://support.microsoft.com/kb/268343

A Simple Approach to Memory Analysis

Introduction

Memory Leaks are a common error in programming, especially when the language used to write the Code has no in-built automatic garbage collection mechanism. A memory leak can greatly reduce the performance of the system by reducing the amount of available memory especially when the amount of memory available in a system is very limited (in the case of portable systems and embedded applications) and when the program runs for long periods of time (such as background tasks on servers). Due to the prevalence of the memory leak bugs, a number of debugging tools such as IBM Rational Purify, Bounds Checker, memwatch etc. have been developed. Another such tool is User Mode Heap Dump (UMDH). The advantage of using UMDH is that it is very light-weight and fairly all the memory leaks in an application can be traced along with the line number in the source code where the memory has been leaked in a simple and easier way.

The UMDH utility dumps information about the heap allocations of a process and this information include:

· the ‘callstack’ for each allocation,

· the number of allocations that are made through that ‘callstack’, and

· the number of bytes that are consumed through that ‘callstack’.

The UMDH utility also helps compare two UMDH logs to provide an analysis of the difference between them. This information is actually used to check whether there is a memory leak or not.


Pre-requisites for using UMDH

Installing the UMDH Utility:

The UMDH utility is included with the Debugging Tools for Windows. It can be downloaded from the following Web site:

http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx

After installing the utility, the System PATH environment variable must be set to the location where the UMDH is installed.

clip_image002

Fig. 1: Setting the System PATH Environment Variable

The Windows Symbol Package for Windows XP must be downloaded from the Microsoft Web Site mentioned below and the path where the symbol files are installed must be added to the ‘_NT_SYMBOL_PATH’ environment variable. This has to be done to get the details of the Windows Function Calls in the Stack Trace.

The Windows Symbol package can be downloaded from the Web Site:

http://www.microsoft.com/whdc/DevTools/Debugging/symbolpkg.mspx

clip_image004

Fig. 2: Setting the ‘_NT_SYMBOL_PATH’ Environment Variable

Then, the Global Flags has to be set to enable the creation of the User Mode Stack Trace Database. This is just to let the operating system know that the kernel needs to track the memory allocations made by the application.

For example, if the heap dump is required for ‘Reg.exe’. First, the stack trace acquisition must be enabled for ‘Reg.exe’. By default, this feature is not enabled. The command to enable this feature is:

clip_image005

clip_image007

Fig. 3: Enabling the Stack Traces for ‘Reg.exe’.

Note: The command does not enable stack tracing for processes that are already running. It only enables the stack tracing for all the future executions of ‘Reg.exe’.

The flag can also be set through the ‘GFLAGS’ user interface (run Gflags.exe without any arguments in the command prompt to get the user interface).

clip_image009

Fig. 4: Enabling the Stack Traces for ‘Reg.exe’ from the GUI of ‘Gflags’ Utility.

The -ust option for ‘gflags’ can be used to disable the stack tracing when the debugging is finished.


Using UMDH

After the program is started, the Process ID (PID) of the process must be determined. The PID of the application can be obtained from the output of the ‘tlist’ application or the Task Manager.

The UMHD utility can be used now to get the information regarding the heap allocations of a process.

The Command to be used is:

clip_image010

For Example,

If the Process ID is 2204 and the Output File Name is Log01.log, the command to be given is:

clip_image011

The complete heap dump of the ‘Reg’ Process is now in the ‘Log01.log’ file. This file shows all the allocations that were made and the call stacks where the allocations were made.

The Heap Dump is obtained after each successive execution of the application or after the execution of a particular feature in the application. The subsequent executions must be equivalent. For example, if a certain procedure is followed [Triggering the events in the GUI or running a specific module in the application etc.] during the first execution of the application, the same must be followed in the subsequent execution.

The general principle of operation is that UMDH is typically run two (or more times), once to capture a “baseline” snapshot of the process after it has finished initializing (as there are expected to always be a number of outstanding allocations while the process is running that would not be normally expected to be freed until process exit time.

UMDH is then run again in a special mode that is designed to essentially do a logical “diff” between the “baseline” snapshot and the “leaked” snapshot, filtering out any allocations that were present in both of them and returning a list of new, outstanding allocations, which would generally include any leaked heap blocks. It matches the back traces from each file and calculates the increase in bytes allocated for each back trace. These are then displayed in descending order of size of leak. The first line of each backtrace output shows the size of the leak in bytes, followed by the (last-first) difference in parentheses.

The Syntax for the Comparison is:

umdh File01 File02 > File03

where File01 and File02 are the Log Files obtained in two different times the former at an earlier time and the latter at a later time. File03 is the File where the Comparison Information is to be saved.

For Example,

umdh File01.log File02.log > Comparison.log

The various options that can be used with the UMDH utility are:

-d : to display the Output in Decimal (default is Hexadecimal).

-v : To get the verbose output which includes the actual back traces as well as summary information.

-l : To get the file and line number information or the traces.

Demo:

I used a Win32 Test Application which leaks Memory after each Command Button Click. After enabling the ‘User Mode Stack Trace Database’, I started the application and its Process ID was ‘408.

I clicked the Command Button Once and executed the UMDH Tool to create a baseline snapshot of the heap allocations using the following command:

clip_image012

Then, I clicked the Command Button again and executed the UMDH Tool to create the second snapshot of the Heap Allocations. The Command used was the same as the above except that the Output File Name was changed to ‘Log02.log’.

Note: As each output File is a discrete entity, data is not appended to the end of each file. So, if a batch file is intended to run every ten minutes, we’ll have to ensure that the output file name is different for each snapshot.

After taking the two snapshots of the heap allocation, the UMDH Tool can be used to compare the two files and create an output file. The Command used was:

clip_image013

Each Log Entry in the ‘Diff.log’ has the Following Syntax:

clip_image014

One such Log Entry had the Following Data:

clip_image015

From the above Output, one can infer that Memory was leaked in the Line No. 219 in the ‘TestAppl01.cpp’ File.

The memory leaks are listed in descending order of bytes leaked; each will be followed by the complete stack trace of the allocation call. Depending on the cause, this may either pinpoint the bug / leak, or at least show a good place to set a breakpoint for debugging.

I’ve embedded the Code for the Sample Application and the Logs which were obtained.

clip_image017


Conclusion

UMDH is a fairly simple tool to use and it can very effectively used to pin-point the location of memory leak. All we need to do is to have the Symbol File ( pdb ) of the Application and the Symbol Files of the Windows DLL’s. I’ve included a very simple application as an example just to drive home the idea of using this tool. This tool even can be used to find memory leaks in an application which has a very large code base.


References

1. http://support.microsoft.com/kb/268343

Text Widget

Copyright © Vinay's Blog | Powered by Blogger

Design by | Blogger Theme by