I use VisualVM every time I need to tackle performance problems with my apps. Really easy interface, and zero setup needed.
It was really nice to have it included as part of the official JDK distribution but, given Visual VM is now an OS project of its own, it's understandable that Oracle want to break free from it. Development, testing, support / ticket management etc. all can be done by the contributors of the project.
Oracle could have linked Visual VM open source project site at the end, though.
It's normal for the JVM to be using more memory than you allocate, I typically see 2-2.5 GB overhead with 1.12 packs.
20 GB does seem wrong though.
But ATM3 is a very popular pack, so I'm wondering why loads of other people aren't having this problem. Have you added any mods to it? If so, those are the #1 suspects.
Are you using custom Java arguments? Try the ones recommended here for Sevtech, they work well for all 1.12 packs.
If you have the technical know-how and are willing to read the documentation then something like VisualVM can be used to track down the specific cause.
Try using VisualVM to see what's happening during GC. You want to see a stable sawtooth pattern on the heap graph. If the teeth keep going up then you've likely got a memory leak.
Java GC is pretty complex. There are a few different GC implementations, and the details of how and why something is GC'd varies between them.
Those details shouldn't be important to you unless you're tuning performance and have very specific needs when it comes to GC. What should concern you is that you're not leaking memory, which can still happen in Java.
You can use VisualVM to analyze your app's memory usage. What you want to see on the heap graph is a sawtooth pattern that's not slowly creeping upwards. That shows that GC is collecting old references like it should and you're not holding onto "phantom" references anywhere.
There is System.gc() to force GC, but it's not something you want to do in a production app.
You could try running that server on your windows machine again and attach visual vm to it. If you're using jdk8 and under, visualvm is included in the jdk. <path to jdk>/bin
I can't imagine what downside there would be to running the JDK instead of the JRE. I suppose a malicious user could compile classes on the machine, but unless your program is reading random class files from the file system for some reason, I think it would be okay. Also if a malicious user can do that, wouldn't you have bigger problems?
Happy to hear alternative views on this.
Having said that, you can just install the specific tools that you want. For example you can just download jvisualvm here, which will give you profiling and JMX. In fact - for jvisualvm - if you specify the right RMI parameters on your app (as system properties) then you don't even need to put the software on the box: you can just connect remotely. Here's a guide on how to do that.
It also has options for authentication and encryption over the wire if you need
I'm almost sure that Shenandoah GC has to be enabled through the java arguments
In any case I still kinda believe it's a GC issue
What you can do is use Visual VM. It's a Java profiler, meaning it's capable of analyzing your game and telling you
Eclipse has a Visual VM plugin and a Java Mission Control one. Those are the ones I know of.
>I've also put at the beginning a value that stores at what time it starts and then at the end get the current time, so be able to get how long it took. I did it so that I could measure performance so my first question may as well be, is that the best way to measure performance?
It's a basic way to notice that something might be worth investigating, but measurement of performance is done using specialized tools called profilers. You can try JVisualVM, this will tell you how many times each method was called and how much time they took to finish.
This is simple to set up. Run the tool, run your program, you will see it appear in the list of local applications, then just right-click and profile. When your program finishes, the tool will ask you to save a snapshot. Then you can analyse the durations.
If needed, you can just add System.in.read();
or something at the beginning of your main method to pause the execution and then continue by pressing enter after you started the profiling.
By the way, your loops and ArrayLists are probably fine, without looking at code it's hard to say either way.
>java.lang.Error: ServerHangWatchdog detected that a single server tick took 300.00 seconds (should be max 0.05)
If a server doesn't tick within X amount of time it will consider the server "crashed". You either increase the time it takes for it to be considered a "Crash" by increasing max-tick-time=in server.properties. If you wish to disable it, set it to -1. This will not fix any lag issues, just prevent the game from crashing if the server does lag.
The lag could be multiple things but the 2 most likely are going to be server hardware or ingame builds.
For ingame builds, you can use Spark or VisualVM (external program). Apart from that, there's not much more I can suggest.
>java.lang.Error: ServerHangWatchdog detected that a single server tick took 60.00 seconds (should be max 0.05)
If a server doesn't tick within 60 seconds it will consider the server "crashed". You either increase the time it takes for it to be considered a "Crash" by increasing max-tick-time=
in server.properties. If you wish to disable it, set it to -1. This will not fix any lag issues, just prevent the game from crashing if the server does lag.
The lag could be multiple things but the 2 most likely are going to be server hardware or ingame builds.
For ingame builds, you can use Spark or VisualVM (external program). Apart from that, there's not much more I can suggest.
Not a JVM expert but here's my 400-foot overview crack at it. Not sure if I'm telling you anything you don't already know:
Also if you're really curious, you can turn JMX on in tomcat and start poking around in the heap and metaspace with something like VisualVM.
It probably means that they haven't updated their JDK and / or updated their job template in a very long time. `jstack` and `jmap` are monitoring commands provided with the JDK. As you can see from the link, these were combined into `jcmd` in JDK 8. I've also been a Java developer since 1999 and I don't think I've ever ran these programs directly and have instead relied on debugging tools provided via my IDE or VisualVM.
Boom. I found the issue. Was a problem with the Sound Filters mod! It made a call every 13 ticks, which syncs right up with what I saw. I didn't use sampler, but rather, used https://visualvm.github.io/ to monitor the java process. For some reason, the output from sampler wasnt actually capturing the problem.
Thanks to all for help!
Nice post!
Note that there is still some low-hanging fruit in terms of performance, most of the time is spent splitting lines with a regular expression (can be verified with the free VisualVM tool):
String array1[] = readLine.split("\s*\|\s*");
This regular expression is compiled for every line of the file. An easy fix without changing the code otherwise is to pre-compile the Regex pattern with Pattern.compile before the "while" loop:
Pattern splitLine = Pattern.compile("\s*\|\s*"); Pattern splitName = Pattern.compile(", ");
and then use splitLine.split(readLine) instead of readLine.split(..regex...). This gives me a ~ 20% improvement on the big file. Trivia: "firstHalfOfName.split(" ")" is OK because String#split contains a optimization for splitting on a single character that is not a regex control character.
But this still does a lot of unnecessary work since a regex is overkill for this simple pattern - you can do e.g. the following with Apache commons-lang3 which cuts runtime compared to the original version in half:
final String[] array1 = StringUtils.splitPreserveAllTokens(readLine, '|'); for (int i = 0; i < array1.length; i++) { array1[i] = StringUtils.strip(array1[i]); }
Dependency:
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
But yeah, if performance is really an issue here this task is a good candidate for parallelization.
I would suggest checking out visualvm. https://visualvm.github.io/. Great program to get a better idea what is going on in the background.
I got some ideas but I'm sure someone with more experience could throw down the knowledge (I'm not very experienced with databases quite yet).
VisualVM or for a more Minecraft specific profiler WarmRoast
https://visualvm.github.io/ https://github.com/sk89q/WarmRoast
They are JVM profilers so you can see which methods are chewing up CPU cycles