VisualVM is a diagnostic tool for troubleshooting java, the underlying platform that Minecraft and modpacks run on. As the name implies, it provides graphical feedback on current load, CPU usage, garbage collection, memory usage, and much more. List of VisualVM Features.

Installing VisualVM

There is a good chance you don't have it installed by default unless you are also a java developer. Find instructions here: https://visualvm.github.io/download.html. Also install a JDK (Java Development Kit) variant of your java distribution. Note that OpenJDK is a brand. It also has a JRE (Java Runtime Environment) distribution.

Connecting VisualVM to java

If the target runs on local machine...

This section is usually targeted towards ordinary users.

On the left of main window you should find a panel that looks like a file tree. Under the "Local" node you should see multiple items. Double left click the one that you think is most probably your target. (hint: it should have a name including the name of your launcher, or the name of minecraft, or forge, or fml)

If the target runs on remote machine...

This section should only be useful for server owners.

This assume you have ssh access to remote machine and your remote machine is running a headless linux. If it has GUI, you could just launch VisualVM on remote machine and operate on its GUI using RDP or VNC.

  1. Configure your ssh client to dynamically forward to remote via any vacant port (e.g. 13333). This will effectively turn your ssh tunnel into a socks4 proxy.
  2. add these to your server start command before -jar: -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.rmi.port=9011 -Djava.rmi.server.hostname=127.0.0.4 -Dcom.sun.management.jmxremote.local.only=false
  3. Ensure you have jstatd on remote machine. If not, install a jdk instead of your old jre. For ubuntu, this means sudo apt install openjdk-8-jdk-headless
  4. Run jstatd on remote machine. You will need to supply an additional file due to sheer java stupidness. Copy these lines to a file on remote machine. Name it something like jstatd.policy
    grant codebase "file:${java.home}/../lib/tools.jar" {
        permission java.security.AllPermission;
    };
    
    Then run sudo jstatd -J-Djava.security.policy=[path-to-jstatd.policy] -p [arbitrary vacant port on remote machine]
  5. In VisualVM (finally) right click Local node, click Add jstatd connection. Click Add Custom in the new popup window. Set Port field to the arbitrary port you chose in the last step. Click OK to confirm the settings and close the popup window.
  6. Configure your VisualVM to use that proxy. Click Tools in toolbar. Click Options. Click Network. Click Manual proxy settings. Set SOCKS Proxy field to 127.0.0.1, and Port field to the port number you assigned in last step. Then CLEAR THE No Proxy hosts FIELD.
  7. Finally you should now see your server process showing up on the left panel. Double left click it.

Troubleshooting

  • Cannot sudo
    • If you run jvm, jstatd and ssh using the same user, you might be able to run jstatd without sudo. Otherwise it won't show up on the jstatd result.
  • Nothing new show up after adding jstatd connection
    • Check your ssh tunnel is running. Check jstatd is running. Check you didn't put the wrong port in proxy config or jstatd connection.
  • Only jstatd itself show up after adding jstatd connection
    • Run jstatd under the same userid as jvm, or use sudo.

Connecting to an instance within container on remote/local machine

TODO

Generating profiling reports

CPU Profiling

These are the report you will first need to look at if you have a fps or tps issue.

  1. Open the VisualVM you just installed. Open GTNH. The order doesn't matter.
  2. Do whatever is necessary to get to the laggy scenario.
  3. Connect to the GTNH instance.
  4. Select Sampler tab. NOT profiler tab.
  5. Wait until the CPU button inside Sampler button is not disabled (i.e. in grey color). Click it.
  6. Remain in laggy scenario for at least 30 seconds. For transient lags, try reproduce it as much as possible in this period.
  7. Click Stop button. Then click Snapshot. Then click the export button (the button with floppy disk icon. should be right below Profiler Snapshot in GUI). Click export snapshot data. Select a location to save it. Send it to a proper developer to understand its content.

Now, you could also just poke at the profile result yourselves. If you are having fps issue, Client Thread is what you are looking for. If you are having tps issue, Server Thread is what you should care about.

Generating thread dump

These are most useful when your minecraft freezes but did not crash.

  1. Open the VisualVM you just installed. Open GTNH. The order doesn't matter.
  2. Do whatever is necessary to get to the deadlock/infinite loop.
  3. Connect to the GTNH instance.
  4. Go to Threads tab. Click 'Thread Dump
  5. Wait a few seconds. A wall of text should now be displayed on the right. Select and copy them all. Paste them on your favorite online paste website, e.g. pastebin, and send the link to a proper developer to understand its content.

Memory Profiling

These are the report you will need to look at if you have a fps or tps issue, as too much garbage could means too much GC

TODO

Heap Dump

ALERT: NEVER SHARE A HEAP DUMP WITH SOMEONE YOU DON'T TRUST. They contain sensitive info on your minecraft account. Alternatively, run the client using offline mode and somehow reproduce the bug.

  1. Open the VisualVM you just installed. Open GTNH. The order doesn't matter.
  2. Do whatever is necessary to get to the troublesome situation.
  3. Connect to the GTNH instance.
  4. Go to Montior tab. Click 'Heap Dump.
  5. Wait a few seconds. A new tab should be opened. Right click the new node in the left side panel. It should be named something like [heap dump] HH:mm:SS and should be a subnode under the node representing your minecraft instance. Click Save as.... The resulting file can be very large... try share it somehow.