Archive

Posts Tagged ‘hotspot’

Garbage collection of the permanent generation (permgen)

November 1st, 2009

There is often confusion around what the permanent generation contains and given its name, whether or not it can be garbage collected. To cut a long story short, the permanent generation can be garbage collected and is where reflective class meta data, as well as string constants are stored.

This blog entry takes a practical approach to answer the following questions:

  • Can the permanent generation be garbage collected?
  • Does the value of -Xmx (the maximum heap size) include the permanent generation?

Can the permanent generation be garbage collected?

Yes it can. There is often the misconception that string constants cannot be garbage collected. However the only requirement that the JVM specification stipulates is that identity comparison works for constant string values. There is no requirement that the constant be the same object throughout the lifetime of the JVM. Hence if there are no references left to a string constant, there is no reason why it cannot be garbage collected.

To prove this take the following code:

 
public class PermGenDemo {
  public static void main(String[] args) {
    int i = 0;
    while (true) {
      ("string-" + ++i).intern();
    }
  }
}

If the above code is run using the following command:

 
$ java -verbose:gc -XX:PermSize=8m -XX:MaxPermSize=64m PermGenDemo

The following output will be seen (note output cut for brevity):

 
[Full GC [PSYoungGen: 32K->0K(28928K)] . . . [PSPermGen: 65535K->6461K(65536K)]]
[Full GC [PSYoungGen: 32K->0K(31168K)] . . . [PSPermGen: 65535K->6461K(65536K)]]

The above conclusively shows that the permanent generation is collected and when it requires collecting, triggers a full collection.

Does the value of -Xmx (the maximum heap size) include the permanent generation?

No it does not. The size of the permanent generation is controlled by the following JVM options:

* -XX:MaxPermSize controls the maximum permanent generation size.
* -XX:PermSize controls the initial permanent generation size.

The permanent generation is like any other generational compartment: it can grow to a maximum, technically can shrink and can also be garbage collected.

To demonstrate that the permanent generation is not included in the maximum heap settings, pmap can be used (e.g. by running pmap <pid> | tail -1).

The following table illustrates the output of pmap using different JVM heap and permanent generation settings:

JVM options pmap output
java -Xms256m -Xmx256m -XX:PermSize=64m -XX:MaxPermSize=64m 512204K
java -Xms512m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=64m 760556K
java -Xms512m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=128m 825188K

In the above -Xms=-Xmx and -XX:PermSize=-XX:MaxPermSize are set deliberately to stop the heap expanding and ensure constant results. The first value of 512204K gives us a base value which takes into account any overhead introduced by native libraries (including the jvm itself) being mapped into memory. The second value of 760556K is an exact increase of 256m, which is exactly how much the heap was increased by. The third value of 825188K is an exact increase of 64m, which is exactly how much the permanent generation was increased by.

The above results clearly show that the settings for permgen are unrelated to that of the heap.

Conclusion

  • The permanent generation can be garbage collected like other generations.
  • The permanent generation is additional memory to the java heap.
  • -XX:MaxPermSize controls the maximum memory used by the permanent generation.
  • -XX:PermSize controls the initial memory used by the permanent generation.

Resources

  1. Java Hotspot VM Options
  2. Presenting the Permanent Generation

java , ,

Detecting all running JVMs

April 5th, 2009

Several well known JVM tools appear to be able to magically detect the Java processes running on a system. Good examples of this are: jps and Visual VM. As of Java 6 it is even possible to find out yourself which Java processes are running on the local machine that you have access to using the Dynamic Attach API. These APIs can be found in the tools.jar (JAVA_HOME/lib/tools.jar).

The following code illustrates how the Dynamic Attach API can be used to list all of the local virtual machine identifiers (which for the HotSpot VM map onto the JVM PID):

 
package uk.co.cooljeff.dynamicattach;
import java.util.List;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
public class JVMFinder {
  public static void main(String[] args) {
    List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list();
    for (VirtualMachineDescriptor vmDescriptor : vmDescriptors) {
      System.out.println("Name: " + vmDescriptor.displayName()
                                                    + " PID: " + vmDescriptor.id());
    }
  }
}

The above gives the following output on my machine (cut out a few for brevity):

 
Name: uk.co.cooljeff.dynamicattach.JVMFinder PID: 21116

I’m about to spoil the fun now for those of you who were hoping to see some wacky OS dependent mechanism or hidden RMI registry for finding this information. The solution is quite simple, the JVM dumps a file containing performance data to a standard location which it uses to work out what JVMs are running on a host.

Specifically the performance data is for jvmstat, however it is this file that forms the basis of the Dynamic Attach implementation that HotSpot uses.

The following piece of code replicates what the LocalVmManager (part of jvmstat) does to locate running Java processes:

 
package uk.co.cooljeff.dynamicattach;
import java.io.File;
import java.io.FilenameFilter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sun.jvmstat.perfdata.monitor.protocol.local.PerfDataFile;
public class JVMDataLocation {
  public static void main(String[] args) throws Exception {
    final Pattern filePattern = Pattern.compile(PerfDataFile.userDirNamePattern);
    final Matcher fileMatcher = filePattern.matcher("");
    FilenameFilter fileFilter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        fileMatcher.reset(name);
        return fileMatcher.matches();
      }
    };
    File[] files = new File(PerfDataFile.getTempDirectory()).listFiles(fileFilter);
    for (File file : files) {
      System.out.println("PerfDataDir: " + file);
    }
  }
}

Which gives the following on my machine:

 
PerfDataDir: /tmp/hsperfdata_root
PerfDataDir: /tmp/hsperfdata_tomcat55
PerfDataDir: /tmp/hsperfdata_jeffsinc

If you take a look at one of these directories you will find 1 file per Java process running by the specific user. The name of the file is the local virtual machine identifier (lvmid) which for HotSpot will correspond to the process id. If you run strings on the file you will see all of the properties relating to that JVM instance.

It is as simple as that, on Linux the JVM simply looks for all files that match: /tmp/hsperfdata_*/*.

Resources:

java , ,