JVM notes

Reference-object (opens in a new tab) classes

var referenceQueue = new ReferenceQueue<Person>();
var referent = new Person("John", "Doe");
var reference = new WeakReference<>(referent, referenceQueue);
  • To mark the Reference whose referent to be garbage collected, there are 3 ways:

    • reference.enqueue()

      The referent will be garbage collected and enqueued immediately.

    • referent = null

      The referent will be garbage collected and enqueued, but not as immediate as reference.enqueue().

    • reference.clear()

      Only clears the referent field, without enqueuing the reference.

  • java.lang.ref.ReferenceQueue

    • A ReferenceQueue is used to track Reference objects whose referent has been garbage collected, by using ReferenceQueue::poll. When a referent is garbage collected, its Reference will be enqued to the ReferenceQueue it was created with.
    • To be placed on a ReferenceQueue, a Reference object must be created with a ReferenceQueue via its Constructor.
    • Soft and weak reference objects can be created with a reference queue or not, but phantom reference objects must be created with a reference queue.
    • You can use ReferenceQueue::poll to check if any references have been garbage collected.
  • Reference types

    • java.lang.ref.SoftReference

      • Keep objects alive provided there’s enough memory.
      • Suitable for implementing a cache for external resources, so the cache will be effective until JVM runs out of memory.
    • java.lang.ref.WeakReference

      • Keep objects alive only while they’re strongly reachable. When they become weakly reachable only, they are eligible for collection.
      • Suitable for implementing a cache for transient data, so the cache be cleared more eagerly.
      • If GC finds that an object is weakly reachable (reachable only through weak references), it'll clear the weak references to that object immediately.
    • java.lang.ref.PhantomReference

      • Phantom reference objects are placed in their reference queue after they become phantomly reachable, but before their reference field is cleared. This is so a program can perform post-finalization cleanup and clear the phantom reference upon completion of the cleanup.
      • Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use of finalize())
      • it can be used instead of a finalize method, guaranteeing that the object is not resurrected during finalization. This allows the object to be garbage collected in a single cycle, rather than needing to wait for a second GC cycle to ensure that it has not been resurrected.
      • A second use is to detect exactly when an object has been removed from memory (by using in combination with a ReferenceQueue object), ensuring that its memory is available, for example deferring allocation of a large amount of memory (e.g., a large image) until previous memory is freed.
      • In Java 8 and earlier versions, the reference needs to be cleared before the memory for a finalized referent can be reclaimed. A change in Java 9 will allow memory from a finalized referent to be reclaimable immediately.
  • Resources

Garbage Collectors

G1

ZGC

Shenandoah GC

Java Memory Model

Metrics

  • Get arguments of a running JVM process

  • GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions

  • java -X shows non-standard options

Examine loaded classes

  • Use JVM option -verbose:class

    [0.688s][info][class,load] ch.qos.logback.classic.Logger source: file:/mnt/c/Users/Takechiyo/.m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar
  • Use Java API

    • Determine the file containing the class

      var clazz = Logger.class;
      var resourceName = clazz.getSimpleName() + ".class";
      System.out.println(clazz.getCanonicalName() + ": " + clazz.getResource(resourceName));
       
      // ch.qos.logback.classic.Logger: jar:file:/C:/Users/Takechiyo/.m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar!/ch/qos/logback/classic/Logger.class
    • Determine the classloader and file containing the class

      private static void examineClass(Class<?> classObject) {
          var fullName = classObject.getName();
          var resourceName = fullName.replaceAll("\\.", "/") + ".class";
          try {
              var clazz = Class.forName(fullName);
              var loader = clazz.getClassLoader();
              System.out.println("Class: " + clazz.getName());
              System.out.println("Loader: " + loader);
       
              var url = ClassLoader.getSystemResource(resourceName);
              System.out.println("Loaded from: " + url);
       
              System.out.println("All locations: ");
              var e = ClassLoader.getSystemResources(resourceName);
              while (e.hasMoreElements()) {
                  url = e.nextElement();
                  System.out.println("   " + url);
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
       
      examineClass(ch.qos.logback.classic.Logger.class);
      /**
        Class: ch.qos.logback.classic.Logger
        Loader: jdk.internal.loader.ClassLoaders$AppClassLoader@77556fd
        Loaded from: jar:file:/C:/Users/Takechiyo/.m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar!/ch/qos/logback/classic/Logger.class
        All locations:
          jar:file:/C:/Users/Takechiyo/.m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar!/ch/qos/logback/classic/Logger.class
      */

Classloaders

Fundamental classloaders

  • Primordial/Bootstrap classloader
    • Loads the most fundamental Java library classes
    • Part of JVM
  • Extension/Platform classloader
    • Typical name: sun.misc.Launcher$ExtClassLoader
    • Security extension
  • Application/System classloader
    • Typical name: sun.misc.Launcher$AppClassLoader / jdk.internal.loader.ClassLoaders$AppClassLoader
    • Most widely used
    • Loads classes and JAR files on the classpath

The parent-delegation model

  • Because class loading is always delegated first to the parent of the class loading hierarchy, the most trusted repository (the core API) is checked first, followed by the standard extensions, then the local files that are on the class path. Finally, classes that are located in any repository that your own class loader can access, are accessible. This system prevents code from less-trusted sources from replacing trusted core API classes by assuming the same name as part of the core API.

Notes

  • You can load classes from a directory or JAR file that is not already on the classpath, by creating your own URLClassLoader instance. This is commonly done to load plugins.
  • The second parameter in the call Class.forName(className, true, loader) ensures that the static initialization of the class happens after loading. You definitely want that to happen.
  • Do NOT use the ClassLoader.loadClass method. It does not run the static initializers.
  • The URLClassLoader loads classes from the file system. If you want to load a class from somewhere else, you need to write your own class loader by extending java.lang.ClassLoader and implementing protected Class<?> findClass(String name) throws ClassNotFoundException.
  • When loading classes dynamically from external sources like plugins, we should use the corresponding Classloader to load target classes to ensure the target URL of the class

Code snippets

Get Classpath Resources

ClassLoader.getSystemResources("")?.collect { URL classPath ->
    def list = []
    new File(classPath.toURI()).traverse(type: FileType.FILES) {
        list << it.path
    }
    list
}
private static List<String> getClassPathResources(String fileExtension) {
    try {
        List<Path> classPaths = EnumerationUtils.toList(ClassLoader.getSystemResources("")).stream().map(u -> {
            try {
                return Paths.get(u.toURI());
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
        return classPaths.stream().flatMap(p -> {
            try {
                return Files.walk(p).filter(d -> Files.isRegularFile(d))
                        .filter(f -> Strings.isNullOrEmpty(fileExtension) || f.toString().endsWith(String.format(".%s", fileExtension)))
                        .map(i -> i.toAbsolutePath().toString());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Bytecode

Determine the version of Java class file

javap -v $class_file | grep version

Bytecode versions matrix

Java SEReleasedMajorSupported majors
1.0.2May 19964545
1.1February 19974545
1.2December 19984645 .. 46
1.3May 20004745 .. 47
1.4February 20024845 .. 48
5.0September 20044945 .. 49
6December 20065045 .. 50
7July 20115145 .. 51
8March 20145245 .. 52
9September 20175345 .. 53
10March 20185445 .. 54
11September 20185545 .. 55
12March 20195645 .. 56
13September 20195745 .. 57
14March 20205845 .. 58
15September 20205945 .. 59
16March 20216045 .. 60
17September 20216145 .. 61
18March 20226245 .. 62
19September 20226345 .. 63

CLI

jar

List files included in a JAR file

  • jar tf $jar_file
    • The listed file path is the identifier you used to reference the file, and it can be used to extract or update the particular file.

    e.g.

    jar tf playground-spring-boot-cli-0.1-SNAPSHOT.jar | grep properties
    90:BOOT-INF/classes/application.properties
    95:META-INF/maven/cq-playground/playground-spring-boot-cli/pom.properties

Extract files from a JAR file

  • jar xvf $jar_file

    Extract all files

  • jar xvf $jar_file [$file1, $file2...]

    Extract specified files, note the file name must contain path from within the archive, file name alone is not enough.

    e.g.

    • jar xf playground-spring-boot-cli-0.1-SNAPSHOT.jar BOOT-INF/classes/application.properties

    Note: unzip can also extract files from a JAR file.

Update a file from a JAR file

jar uf $jar_file [$file1, $file2...]

javac

Show all lint keys

javac --help-lint
The supported keys for -Xlint are:
    all                  Enable all warnings
    auxiliaryclass       Warn about an auxiliary class that is hidden in a source file, and is used from other files.
    cast                 Warn about use of unnecessary casts.
    classfile            Warn about issues related to classfile contents.
    deprecation          Warn about use of deprecated items.
    dep-ann              Warn about items marked as deprecated in JavaDoc but not using the @Deprecated annotation.
    divzero              Warn about division by constant integer 0.
    empty                Warn about empty statement after if.
    exports              Warn about issues regarding module exports.
    fallthrough          Warn about falling through from one case of a switch statement to the next.
    finally              Warn about finally clauses that do not terminate normally.
    lossy-conversions    Warn about possible lossy conversions in compound assignment.
    missing-explicit-ctor Warn about missing explicit constructors in public and protected classes in exported packages.
    module               Warn about module system related issues.
    opens                Warn about issues regarding module opens.
    options              Warn about issues relating to use of command line options.
    output-file-clash    Warn when an output file is overwritten during compilation. This can occur, for example,
                         on case-insensitive filesystems. Covers class files, native header files, and source files.
    overloads            Warn about issues regarding method overloads.
    overrides            Warn about issues regarding method overrides.
    path                 Warn about invalid path elements on the command line.
    processing           Warn about issues regarding annotation processing.
    rawtypes             Warn about use of raw types.
    removal              Warn about use of API that has been marked for removal.
    requires-automatic   Warn about use of automatic modules in the requires clauses.
    requires-transitive-automatic Warn about automatic modules in requires transitive.
    serial               Warn about Serializable classes that do not have a serialVersionUID field.
                         Also warn about other suspect declarations in Serializable and Externalizable classes and interfaces.
    static               Warn about accessing a static member using an instance.
    strictfp             Warn about unnecessary use of the strictfp modifier.
    synchronization      Warn about synchronization attempts on instances of value-based classes.
    text-blocks          Warn about inconsistent white space characters in text block indentation.
    this-escape          Warn when a constructor invokes a method that could be overriden in an external subclass.
                         Such a method would execute before the subclass constructor completes its initialization.
    try                  Warn about issues relating to use of try blocks (i.e. try-with-resources).
    unchecked            Warn about unchecked operations.
    varargs              Warn about potentially unsafe vararg methods.
    preview              Warn about use of preview language features.
    none                 Disable all warnings

Can be turned on with javac -Xlint:$key

java

java - cheatsheet

java - Specify system properties
java -D$property_name=$property_value $class_name

Use jcmd $JVM_PID VM.system_properties to verify

java - Display system property settings
  • java -XshowSettings:properties
java - Use @ prefix to reference files containing arguments
  • Use the @ prefix to identify an argument file that contains java options and class names.

    e.g. java @path1/options @path2/classes

java - Debug SSL/TLS Connections
  • Use system property javax.net.debug=ssl, for options check reference below.

    # The current options are:
     
        all: Turn on all debugging
        ssl: Turn on SSL debugging
     
    # The following can be used with the ssl option to select what type of debug information to print:
     
        defaultctx: Print default SSL initialization
        handshake: Print each handshake message
        keygen: Print key generation data
        keymanager: Print key manager tracing
        pluggability: Print pluggability tracing
        record: Enable per-record tracing
        respmgr: Print status response manager tracing
        session: Print session activity
        sessioncache: Print session cache tracing
        sslctx: Print SSLContext tracing
        trustmanager: Print trust manager tracing
     
    # Messages generated from the handshake option can be widened with these options:
     
        data: Hex dump of each handshake message
        verbose: Verbose handshake message printing
     
    # Messages generated from the record option can be widened with these options:
     
        plaintext: Hex dump of record plaintext
        packet: Print raw SSL/TLS packets
  • Resources

java - View security properties, security providers, and TLS-related settings
java -XshowSettings:security
java - List security debugging options
java -Djava.security.debug=help
Apply additional JVM options via JDK_JAVA_OPTIONS and JAVA_TOOL_OPTIONS

JDK_JAVA_OPTIONS

  • Only works for Java 9+ and the java CLI

JAVA_TOOL_OPTIONS

  • In addition to java, also works for other Java tools such as jar and javac
# Set environment variable
export JDK_JAVA_OPTIONS="-Dspring.profiles.active=dev"
 
# Run JVM process
mvn spring-boot:run
 
# A message will display as confirmation
NOTE: Picked up JDK_JAVA_OPTIONS: -Dspring.profiles.active=dev

Caveat: JAVA_OPTS is not standard and not guaranteed to work.

JVM Options

JVM Options - GC
JVM Options - Logging
JVM Options - Memory Settings
  • Heap

    • -Xms is equivalent to -XX:InitialHeapSize.

    • -Xmx is equivalent to -XX:MaxHeapSize.

    • -Xmx should be between 80% and 100% of the machine's physical memory. If you set -Xmx too small, the application server may fail with an OutOfMemory error. If you set -Xmx too large, the memory's footprint is larger and you run the risk of Java's heap being swapped out, causing other performance problems.

    • -Xms should be approximately half of the -Xmx setting. If you have historical data about your application server's stable memory-usage point, then set -Xms to be around that value.

  • Metaspace (formely PermGen)

    • -XX:MaxMetaspaceSize is the maximum amount of native memory that can be allocated for class metadata. The default value depends on the platform.

    • -XX:MetaspaceSize is the initial amount of native memory that can be allocated for class metadata. The default size of is platform-dependent and ranges from 12 MB to about 20 MB.

    • -XX:MaxMetaspaceFreeRatio is the maximum percentage of class metadata free space to class metadata used space after a garbage collection. The default value is 70.

    • -XX:MinMetaspaceFreeRatio is the minimum percentage of class metadata free space to class metadata used space after a garbage collection. The default value is 40.

    • If you observe classes being unloaded during full garbage collections, you should use -XX:PermSize and -XX:MaxPermSize command line options to size the permanent generation space. To avoid full garbage collections that may expand or shrink the committed size of the permanent generation space, set -XX:PermSize and -XX:MaxPermSize to the same value.

    • Resources

JVM Options - Compiler (JIT)
  • -XX:+PrintCompilation prints a message to the console when a method is compiled.
  • -XX:+PrintCompilation2 prints a message to the console when a method is compiled, and includes the time it took to compile the method.
JVM Options - Performance - based on JMC Automated Analysis Results
  • Java Application

    • Memory

      • Free Physical Memory

        Having little free memory may lead to swapping, which is very expensive. To avoid this, either decrease the memory usage or increase the amount of available memory.

    • Exceptions

      • Thrown Errors

        Investigate the thrown errors to see if they can be avoided. Errors indicate that something went wrong with the code execution and should never be used for flow control.

  • JVM Internals

    • Stackdepth Setting

      Some stack traces were truncated in this recording. If more detailed traces are required, increase the -XX:FlightRecorderOptions=stackdepth=<value> value.

    • GC Configuration

      • Compressed Oops

        Not using Compressed Ordinary Object Pointers when the heap size is below 32 GB wastes memory and will lead to unnecessary cache pressure. Use the JVM argument -XX:+UseCompressedOops to enable this feature.

        Refer to OpenJDK Wiki - CompressedOops (opens in a new tab) for details.

  • Environment

    • Processes

      • Competing Processes

        If this is a server environment, it may be good to only run other critical processes on that machine.

JVM Options - Resources

jps

jps - List all local JVM processes

jps -lvm

jcmd

jcmd - List all local JVM processes

jcmd / jcmd -l
# e.g.
$ jcmd
3157 org.gradle.launcher.GradleMain bootRun
2710 org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.5
5145 jdk.jcmd/sun.tools.jcmd.JCmd
3390 cq.playground.spring.poc.kafka.nonreactive.MainApp

jcmd - List all diagnostic commands for a specific process

jcmd $PID [help]

If PID is 0, the command is sent to all JVM processes

# e.g.
$ jcmd 3390
3390:
The following commands are available:
Compiler.CodeHeap_Analytics
Compiler.codecache
Compiler.codelist
Compiler.directives_add
Compiler.directives_clear
Compiler.directives_print
Compiler.directives_remove
Compiler.perfmap
Compiler.queue
GC.class_histogram
GC.finalizer_info
GC.heap_dump
GC.heap_info
GC.run
GC.run_finalization
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop
JFR.view
JVMTI.agent_load
JVMTI.data_dump
ManagementAgent.start
ManagementAgent.start_local
ManagementAgent.status
ManagementAgent.stop
System.native_heap_info
System.trim_native_heap
Thread.dump_to_file
Thread.print
VM.cds
VM.class_hierarchy
VM.classes
VM.classloader_stats
VM.classloaders
VM.command_line
VM.dynlibs
VM.events
VM.flags
VM.info
VM.log
VM.metaspace
VM.native_memory
VM.set_flag
VM.stringtable
VM.symboltable
VM.system_properties
VM.systemdictionary
VM.uptime
VM.version
help

jcmd - Help for a specific diagnostic command

jcmd <PID/Main Class> help $command

eg: jcmd 38388 help VM.version

jcmd - List system properties of a JVM process

jcmd $PID VM.system_properties | sort
# e.g.
$ jcmd 3390 VM.system_properties
3390:
#Sun Feb 04 15:06:55 AEDT 2024
CONSOLE_LOG_CHARSET=UTF-8
FILE_LOG_CHARSET=UTF-8
LOG_FILE=/tmp/spring.log
LOG_PATH=/tmp
PID=3390
catalina.base=/tmp/tomcat.8080.470854316564232780
catalina.home=/tmp/tomcat.8080.470854316564232780
catalina.useNaming=false
file.encoding=UTF-8
file.separator=/
java.awt.headless=true

jcmd - List JVM flags

jcmd $PID VM.flags | tr " " "\n" | sort

or

jinfo -flags $PID | tr " " "\n" | sort

jinfo

jinfo - List system properties of a JVM process

jinfo -sysprops $PID | sort

jinfo - Print the value of the specified VM flag

jinfo -flag $name

jinfo - Enable/Disable the specified VM flag

jinfo -flag [+|-]$name

JFR (Java Flight Recorder)

JMX

JDP

GUI Tools

JMC (JDK Mission Control)

jol (Java Object Layout)

VisualVM

References