Memory
Java does not require, or allow, programmers to explicitly allocate and reclaim memory. The JVM will allocate memory when a new object is created, and will reclaim the memory once there are no more references to the object.
Java does not allow pointer arithmetic. Memory deallocation is performed by a thread executing in the JVM called the garbage collector (GC).
The garbage collection algorithm used for is not specified in the JVM specification. Different JVM implementations may use different GC algorithms.
However, all of these algorithms require the sweeping of memory to identify objects that are no longer referenced. Most also involve a compaction phase where referenced objects are copied to a particular area of memory to reduce fragmentation.
More details about garbage collection can be found in...
"Improving Java Application Performance and Scalability by Reducing Garbage Collection Times and Sizing Memory"There is also a JDK 1.4.1 version of the article
Creating an object consumes system resources, because the JVM must allocate memory and initialize the object.
Reclaiming memory using the garbage collector uses CPU time.
Garbage collection occurs asynchronously when free memory reaches threshold values, and it cannot be explicitly scheduled programmatically. A call to the System.gc() method will request that the JVM performs garbage collection. However, this is not guaranteed to happen immediately or within any specified time period.
To minimize memory usage, particularly object creation and destruction...
- Object creation
Don't create objects prematurely if there is a possibility that they will not be needed. For example, if the object is only used in one path of an if statement, then create the object inside that path rather that outside the if statement - lazy initialization. If the same object can be reused inside a loop body, then declare and instantiate it outside the loop rather than inside the loop, to avoid creating and destroying a number of objects of the same class.
- Object pools
If objects of the same class are being repeatedly created and destroyed, it can be beneficial to create an object pool that allows the objects to be reused. Classes whose objects will be used in a pool need an initializer, so that objects obtained from the pool have some known initial state. It is also important to create a well-defined interface to the pool to allow control over how it is used.
Note IBM WAS Enterprise V5.1 provides Object Pools for pooling application defined objects or basic JDK types. It will benefit an application which tries to squeeze every ounce of performance gain out of the system.
- Appropriate sizing for collections
Although the Java runtime environment will dynamically grow the size of collections such as...
- java.util.Vector
- Java.util.Hashtable
...it is more efficient if they are appropriately sized when created. Each time the collection size is increased, its size is doubled so when the collection reaches a stable size it is likely that its actual size will be significantly greater than required. The collection only contains references to objects rather than the objects themselves, which minimizes the overallocation of memory due to this behavior.
- Temporary objects
Developers should be aware that some methods such as toString() methods can typically create a large number of temporary objects. Many of the objects may be created in code that you don't write yourself, such as library code that is called by the application.
- Use of static and final variables
When a value is used repeatedly and is known at compile time, it should be declared with the static and final modifiers. This will ensure that it will be substituted for the actual value by the compiler. If a value is used repeatedly but can be determined only at runtime, it can be declared as static and referenced elsewhere to ensure that only one object is created. Note that the scope of static variables is limited to the JVM. Hence if the application is cloned, care needs to be taken to ensure that static variables used in this way are initialized to the same value in each JVM. A good way of achieving this is the use of a singleton object. For example, an EJB initial context can be cached with a singleton (as suggested in 18.7, Enterprise JavaBeans) using the following code fragment:
public class EJBHelper { private static javax.naming.InitialContext initialContext= null; public javax.naming.InitialContext getInitialContext() { f (initialContext = null) { initialContext = new javax.naming.InitialContext(); return initial Context } } }- Object references
Although memory does not have to be explicitly deallocated, it is still possible to effectively have "memory leaks" due to references to objects being retained even though they are no longer required. These objects are commonly referred to as loitering objects. Object references should be cleared once they are no longer required, rather than waiting for the reference to be implicitly removed when the variable is out of scope. This allows objects to be reclaimed sooner. Care should be taken with objects in a collection, particularly if the collection is being used as a type of cache. In this case, some criteria for removing objects from the cache is required to avoid the memory usage constantly growing.
Another common source of memory leaks in Java is due to programmers not closing resources such as Java Database Connectivity (JDBC), JMS and Java Connector Architecture (JCA) resources when they are no longer required, particularly under error conditions. More information about the use of JDBC resources is provided in 18.8, Database access. It is also important that static references be explicitly cleared when no longer required, because static fields will never go out of scope. Since WAS applications typically run for a long time, even a small memory leak can cause the Java Virtual Machine to run out of free memory. An object that is referenced but no longer required may in turn refer to other objects, so that a single object reference can result in a large tree of objects which cannot be reclaimed.
The profiling tools available in IBM WebSphere Studio Application Developer V5.1.1, which are described in Chapter 17, Development-side performance and analysis tools, can help to identify memory leaks. Other tools that can be used for this purpose include Rational PurifyŽ, Sitraka JProbe (by Quest Software), and Borland OptimizeIt.
- Vertical clustering
Most current garbage collection implementations are partially single threaded (during the heap compaction phase). This causes all other program threads to stop, potentially increasing the response times experienced by users of the application. The length of each garbage collection call is dependent on numerous factors, including the heap size and number of objects in the heap. Thus as the heap grows larger, garbage collection times can increase, potentially causing erratic response times depending on whether a garbage collection occurred during a particular interaction with the server. The effect of this can be reduced by using vertical scaling and running multiple copies of the application on the same hardware.
This can provide two benefits: first, the JVM for each member of the cluster will only require a smaller heap, and secondly, it is likely that while one JVM is performing garbage collection, the other one will be able to service client requests as the garbage collection cycles of the JVMs are not synchronized in any way. However, any client requests that have been directed by workload management to the JVM (doing garbage collection) will be affected.
Refer to 3.7, Vertical scaling for more information on vertical clustering.
Prev | Home | Next
WebSphere is a trademark of the IBM Corporation in the United States, other countries, or both.
IBM is a trademark of the IBM Corporation in the United States, other countries, or both.
Rational is a trademark of the IBM Corporation in the United States, other countries, or both.