Skip to main content

Command Palette

Search for a command to run...

Mission 1 - JVM scouting

Published
2 min read
I

From Java I feel the need The need for speed

This is text version for the first stream of JTop-Gun channel. The link to the video recording:

<link here>

Let's turn and burn...

Getting basic information about JVM

And we start with "Hello world" and put it into sleep :)

package org.jtopgun;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(1_000_000_000);
        System.out.println("Hello world!");
    }
}

Questions: how many threads are running right now? How much memory does our "Hello world" occupy? What version of JVM is it running? What GC?

JCONSOLE

JDK gives tools to answer all these questions. And basic tool from JDK to get quite a lot of info is

./jconsole

JPS / JCMD

If we don't have graphical interface, let's see at command line tools which are available.

First let's identify PID for our program. Run

./jps

You will see all JVM running on your machine. JPS stands for JVM process state.

And now let's try

./jcmd

You will see a lot of available commands and can play with them using

./jcmd <pid> <command>

GETTING THREAD DUMP

Now let's see current stack trace of our sleeping beauty. Here are our command line options:

./jstack <pid>
./jcmd 10364 Thread.print

Or you could use jconsole and you will see something like

I have 16 threads, but depending on your Java version, JVM vendor, machine, it can be very different.

There will be a different article describing all of them, today we focus on Reference Handler and Finalizer. Why they are needed? Peter Lawrey gives very good answer for that here https://stackoverflow.com/questions/7658670/understanding-the-reference-handler-thread

But in short, GC is creating linked list of references ready to be removed. Reference Handler will put them in appropriate queue, and Finalizer thread will execute code which is in finalize() method.

WHY YOU MUST NOT USE FINALIZE()

Now, let's update our hello world app like that:

package org.jtopgun;

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread newThread = new Thread(() -> {
            while (true) {
                List arrayList = new ArrayList();
                System.out.println(arrayList.size());
            }
        });
        newThread.start();
        Thread.sleep(1_000_000_000);
    }
}

Basically we start creating garbage in second thread quickly and indefinitely, then memory graph will look approximately like that:

Very much expected - garbage is being created and normally removed. Now let's add another class:

package org.jtopgun;

public class ClassWithFinalizer {

    @Override
    public void finalize() throws InterruptedException {
        Thread.sleep(1);//1 milisecond finalize method
    }
}

And rerun the application

We see a stable heap growth. Outcome - never use finalize() method :)