Take a look at Beginners.co.uk Take a look at Beginners.co.uk

Java: Performance Tuning and Memory Management Part 4 - Memory Utilization
Submitted By: Wrox Books
Published Date: 9th March 2001 
Viewed: 34,671 times
Full computer related training courses are available in our membership area. To view over 400 Beginners.co.uk courses, click here. An annual training membership costs only £99 OR $149.
Although Java's performance problems have often been exaggerated, it is true that Java programs sometimes use a large amount of memory.
 
In fact, if you execute the following trivial application on Window NT 4.0 with release 1.2.2 of JavaSoft's JVM, the process uses approximately 4 megabytes of memory:
public class Test {

  public static void main(String[] args) {
    Object o = new Object();
    synchronized (o) {
      try {
        o.wait();
      } catch (Exception e) {};
    }
  }

}

Once you begin to write code that actually does something, the amount of memory used can become substantially larger. To some extent, the amount of memory your application uses is determined by its architecture, but there are ways that you can determine where memory is being used and steps that can be taken to reduce memory utilization.

For example, the HPROF utility was used earlier to identify the execution paths within an application that were responsible for allocating most of the heap space that was used. In addition, commercial software applications such as OptimizeIt provide information similar to that created by HPROF, but it can actually update the information dynamically while an application is running. You can view:

  • Information that shows the type of object using the most space:

  • The execution path(s) responsible for the allocations:

  • A graph showing storage allocations over time:

You may sometimes be surprised at how much storage certain types of objects require in Java. For example, instances of java.awt.Image tend to be much larger than the compressed GIF or JPEG files from which they're created.

One way that you can reduce the amount of memory needed without modifying your code is to use an optimizer such as DashO from preEmptive Solutions (http://www.preemptive.com/). This type of optimizer creates modified versions of your application's class files, removing unused methods, fields, classes, and constants. However, much of the reduction often comes from actually changing the names of the classes, methods, and fields within your class files so that they're smaller than those used in the source code. For example, DashO could change all references to a method named generateAnnualReport() into references to a method called gar().

Although meaningful names are important for coding and debugging purposes, they cause the JVM to use more storage at execution time, but optimizer products such as DashO allow you to reduce that problem. Note that these products do not modify your source code, but only the class files created during compilation of your source. However, since they do convert class and method names that were meaningful to you into names that are not, you normally should only use this type of optimization after your debugging is largely complete. Otherwise, the stack trace information you see when an exception is thrown may be confusing and meaningless.

In addition to reducing the size of your application code, this type of optimization provides one other advantage. Compiled Java code stored in class files is normally easy to disassemble and reverse engineer, meaning that when you distribute your application code, it's possible for the users to recreate, examine, and copy your source. Although it's not possible to prevent this entirely, the conversion of field, method, and class names into short and meaningless (or otherwise confusing) names makes it impractical. This act of making compiled Java class files more difficult to reverse engineer is called obfuscation, and can be accomplished using DashO or any of a number of other commercial software products.

Heap Management

When a JVM is executed, it obtains a large area of memory from the underlying operating system. That area is called the heap, and Java performs its own memory management by allocating areas of the heap when memory is needed. The default size of the heap varies from one JVM implementation to the next, but you can determine its current size using the Runtime class's totalMemory() method as shown below:

System.out.println("Heap size is " + Runtime.getRuntime().totalMemory());

It's similarly easy to find out how much of the heap space is unused by calling the freeMemory() method as in the following code:

System.out.println("Available memory: " +
                   Runtime.getRuntime().freeMemory());

At this point, you may be wondering what will happen if your Java program uses all of the memory on the heap. An easy way to find out is to deliberately create a program that does so, and an example of how this can be done is shown below:

public class HeapTest {

  public static void main(String[] args) {
    Runtime rt = Runtime.getRuntime();
    java.util.Vector v = new java.util.Vector();
    while (true) {
      long size = rt.freeMemory();
      System.out.println("Total memory = " + rt.totalMemory() 
                         + ", free memory = " + size);
      byte[] buffer = new byte[(int) size];
      v.addElement(buffer);
    } 
  } 

}

This program loops indefinitely, displaying the amount of total and free memory and creating a byte array that's as large as the total amount of available memory. Each time the buffer is created, it's added to a Vector so that the space it uses cannot be reclaimed by the garbage collector during execution. Although the exact results will vary based on the JVM you use, this program will display output similar to that shown below:

Total memory = 1048568, free memory = 754944
Total memory = 2097144, free memory = 1139800
Total memory = 3403768, free memory = 1306672
Total memory = 5414904, free memory = 2011120
Total memory = 8507384, free memory = 3092464
Total memory = 12701688, free memory = 4194240
Total memory = 16895992, free memory = 4194288
Total memory = 21090296, free memory = 4194288
Total memory = 25284600, free memory = 4194288
Total memory = 29478904, free memory = 4194288
Total memory = 33673208, free memory = 4194288
Total memory = 37867512, free memory = 4192912
Total memory = 42061816, free memory = 4195624
Total memory = 46256120, free memory = 4194288
Total memory = 50450424, free memory = 4194288
Total memory = 53899256, free memory = 3448816
Exception in thread "main" java.lang.OutOfMemoryError
        at HeapTest.main(HeapTest.java, Compiled Code)

Since a buffer as large as the available memory is allocated each time the code within the loop is executed, you might have expected the program to terminate on the first or second iteration. What happened instead was that the total memory (the size of the heap) automatically increased so that the memory could be allocated each time. Eventually, however, no more memory could be allocated and an OutOfMemoryError was thrown.

Continued...



 

Next Page



RELATED PAGES