[HN Gopher] JVM Options Explorer
       ___________________________________________________________________
        
       JVM Options Explorer
        
       Author : 0x54MUR41
       Score  : 164 points
       Date   : 2026-04-12 10:29 UTC (12 hours ago)
        
 (HTM) web link (chriswhocodes.com)
 (TXT) w3m dump (chriswhocodes.com)
        
       | Hendrikto wrote:
       | 1843 options is too many. You could never even consider all of
       | the possible combinations and interactions, let alone test them.
       | 
       | I have really come to appreciate modern opinionated tooling like
       | gofmt, that does not come with hundreds to thousands of knobs.
        
         | tezza wrote:
         | How is this different to system tuning parameters in Linux
         | /proc, FreeBsd, Windows Registry, Firefox about:config,
         | sockopt, ioctl, postgres?
         | 
         | Zillions of options. Some important, some not
        
         | mzi wrote:
         | One of my nerd-quizzes I hade at interviews before was "what
         | letters in what case are NOT flags to GNU ls".
        
           | eru wrote:
           | The answer is 'man ls'. And: 'almost all letters of unicode'.
        
         | deepsun wrote:
         | Just because you have more features and ways to use them. Say I
         | like to use a different garbage collector for a tool.
        
         | RadiozRadioz wrote:
         | I don't think modernity is a noteworthy factor as to whether
         | tooling is opinionated.
        
         | elric wrote:
         | In what way is gofmt remotely comparable to a JVM?
         | 
         | In reality the number of options is significantly smaller than
         | the 1843 you mentioned. The list contains boatloads of
         | duplicates because they exist for multiple architectures. E.g.
         | BackgroundCompilation is present on 8 lines on the OpenJDK 25
         | page: aarch64, arm, ppc, riscv, s390, x86 and twice more
         | without an architecture.
        
           | avianlyric wrote:
           | gofmt isn't really comparable to the JVM, but it is a really
           | strong expression of the opinionated tooling GoLang has.
           | 
           | While gofmt is "just" a formatting tool. The interesting part
           | is that go code that doesn't follow the go formatting
           | standard is rejected by the go compiler. So not only does
           | gofmt not have knobs, you can't even fork it to add knobs,
           | because the rest of the go ecosystem will outright reject
           | code formatted in any other way.
           | 
           | It's a rather extreme approach to opinionated tooling. But
           | you can't argue with the results, nobody writing go on any
           | project ever worries about code formatting.
        
             | kfuse wrote:
             | They do worry, they just can't do anything about it. Like
             | the fact that error handling code takes at least three
             | lines no matter how trivial it is. I'm sure error handling
             | would not be critisized nearly as much if it didn't consume
             | so much vertical space and could fit in one line, which go
             | compiler does allow.
        
             | elric wrote:
             | That's all well and good, but entirely irrelevant to the
             | number of options a JVM should reasonably have.
        
               | bram98 wrote:
               | .
        
             | parsd wrote:
             | I don't believe the Go compiler would reject unformatted
             | code. The compiler has its own set of rules for what it
             | views as syntactically correct code, but these rules have
             | nothing to do with gofmt's formatting rules.
             | 
             | For example, it's the compiler and not gofmt that dictates
             | that you must write a curly brace only on the same line of
             | an "if" statement. If you put it on the next line, you
             | don't have unformatted code - you have a syntax error.
             | 
             | However, the compiler doesn't care if you have too much
             | whitespace between tokens or if you write your slice like
             | []int{1, 2,3,4}, but gofmt does.
             | 
             | We could say the rules of the compiler and gofmt don't even
             | overlap.
        
         | tomaytotomato wrote:
         | It's a result of Java being required to run on many different
         | OS environments (Oracle, Redhat, Windows, RISC/ARM/x86), along
         | with user constraints and also business requirements.
         | 
         | In a way you can use this list of JVM options to illustrate how
         | successful Java has become, that everyone needs an option to
         | get it to work how they like it.
         | 
         | As a Java dev, I have maybe used about 10-15 of them in my
         | career.
         | 
         | The weirdest/funnest one I used was for an old Sun Microsystems
         | Solaris server which ran iPlanet, for a Java EE service.
         | 
         | Since this shared resources with some other back of office
         | systems, it was prone to run out of memory.
         | 
         | Luckily there was a JVM option to handle this!
         | 
         | -XX:OnOutOfMemoryError="<run command>"
         | 
         | It wasn't too important so we just used to trigger it to
         | restart the whole machine, and it would come back to life.
         | Sometimes we used to mess about and get it to send funny IRC
         | messages like "Immah eaten all your bytez I ded now, please
         | reboot me"
        
           | nkzd wrote:
           | Which JVM options do you use the most?
        
             | cogman10 wrote:
             | Heap size, GC algorithm.
             | 
             | I suggest most people never touch almost any other options.
             | (Flight recording and heap dumps being the exception).
        
               | marginalia_nu wrote:
               | GC threads are generally often useful on multi-tenant
               | systems or machines with many cores, as Java will
               | default-size its thread pools according to the number of
               | logical cores. If the server has 16 or more cores, that's
               | very rarely something you want, especially if you run
               | multiple JVMs on the same host.
               | 
               | Not JVM options, but these are often also good to tune:
               | -Djdk.virtualThreadScheduler.parallelism
               | -Djdk.virtualThreadScheduler.maxPoolSize
               | -Djava.util.concurrent.ForkJoinPool.common.parallelism
               | 
               | In my experience this often both saves memory and
               | improves performance.
        
               | cyberpunk wrote:
               | You can get into difficulty with kubernetes here, as your
               | jvm will detect all cores on the node but you may have
               | set a resources limit on the pod/whatever, so it'll
               | assume it can spend more time doing stuff than it
               | actually can, so often times it's quite necessary to tune
               | some things to prevent excessive switching etc.
        
               | dpratt wrote:
               | Modern JVMs will detect orchestrator-set cgroup limits
               | and size themselves accordingly. If you, for example, set
               | a cpu limit for a pod to "1", the JVM will size itself as
               | if it was running on a single core machine.
        
               | vips7L wrote:
               | Afaik this was fixed a long time ago.
        
           | Hendrikto wrote:
           | > As a Java dev, I have maybe used about 10-15 of them in my
           | career.
           | 
           | So do we really need multiple thousand? Having all of them
           | also makes finding the few you actually need much more
           | difficult.
        
             | KronisLV wrote:
             | > So do we really need multiple thousand?
             | 
             | Assuming that you don't need 99.9% of them (they should
             | have sane defaults that you never have to change or even
             | learn that they exist or what they are) until that super
             | rare case when one will save your hide, I'd lean towards
             | yes.
             | 
             | In other words, they might as well be an escape hatch of
             | sorts, that goes untouched most of the time, but is there
             | for a reason.
             | 
             | > Having all of them also makes finding the few you
             | actually need much more difficult.
             | 
             | This is a good point! I'd expect the most commonly changed
             | ones (e.g. memory allocation and thread pools) to be
             | decently well documented, on the web and in LLM training
             | data sets. Reading the raw docs will read like noise,
             | however.
        
             | nradov wrote:
             | Did you RTFM? It's not difficult to find the few you
             | actually need.
        
         | eru wrote:
         | > You could never even consider all of the possible
         | combinations and interactions, let alone test them.
         | 
         | Nobody has ever tested all possible inputs to 64 bit
         | multiplication either. You can sample from the space.
        
           | pixl97 wrote:
           | Eh that sounds a bit different to me, multiplication should
           | be roughly the same operator on each test, these are wildly
           | different functions.
        
             | deepsun wrote:
             | You forgot about NaNs (all of them), infinities and
             | positive/negative zeros. Tests warranted.
        
               | MaxBarraclough wrote:
               | Don't forget the Intel floating-point division bug from
               | the 90s.
               | 
               | https://en.wikipedia.org/wiki/Pentium_FDIV_bug
        
         | Geezus_42 wrote:
         | As a sysadmin, not developer, I hate Java almost as much as
         | Windows. The error messages Java apps produce are like coded
         | messages that you have to decipher.
         | 
         | I.E. Instead of "<DOMAIN> TLS Handshake failed" it will be
         | something like "ERROR: PKIX failed". So now I have to figure
         | out that PKIX is referring to PKI and it would make too much
         | sense to provide the domain that failed. Instead I have to play
         | the guessing game.
        
           | deepsun wrote:
           | I hate when tools only produce generic "TLS Handshake failed"
           | instead of saying why exactly it failed, where is the
           | problem.
        
             | thunky wrote:
             | Sounds like you'd both be happy if the tool produced both.
        
               | appplication wrote:
               | This is why stack traces exist. But I agree Java seems to
               | not really have a culture of "make the error message
               | helpful", but instead preferring "make the error message
               | minimal and factual".
               | 
               | For what it's worth, the rise of helpful error messages
               | seems to be a relatively new phenomenon the last few
               | years.
        
               | Geezus_42 wrote:
               | Sounds to me that deepsun and I are in agreement that an
               | error message should tell you what the actual error was.
               | 
               | I.E. ERROR: TLS handshake failed: <DOMAIN> certificate
               | chain unverified
        
             | kitd wrote:
             | This is the kind of scenario that is served better by
             | Go/C-style error values than exceptions. Error values
             | facilitate and encourage you to log what you were doing at
             | the precise point when an error occurs. Doing the same with
             | exceptions idiomatically often requires an exception
             | hierarchy or copious amounts of separate try/catches.
             | 
             | The difference really becomes apparent when trying to debug
             | a customer's problem at 3am (IME).
        
           | well_ackshually wrote:
           | So your issue isn't with Java, just with shit error messages
           | and devs clearing the exception stack.
        
         | pron wrote:
         | These are all the options that have ever existed, including
         | options that are or were available only in debug builds used
         | during development and diagnostic options. There are still a
         | few hundred non-diagnostic "product" flags at any one time, but
         | most are intentionally undocumented (the list is compiled from
         | the source code [1]) and are similar in spirit to
         | compiler/linker configuration flags (only in Java, compilation
         | and linking are done at runtime) and they're mostly concerned
         | with various resource constants. It is very rare for most of
         | them to ever be set manually, but if there's some unusual
         | environment or condition, they can be helpful.
         | 
         | [1]:
         | https://github.com/openjdk/jdk/blob/master/src/hotspot/share...
        
         | quotemstr wrote:
         | In the age of LLMs coupled with open source software, option
         | count is unlimited. I fork FOSS projects and modify them for my
         | own use all the time. Sometimes, with an agent, doing so is
         | even easier than finding the "right" knob.
        
         | fHr wrote:
         | Thank god you have no say in where modern tooling is heading,
         | at the creator of the site, absolute right choice to leave it
         | up to the user to chose all options.
        
         | TacticalCoder wrote:
         | > 1843 options is too many. You could never even consider all
         | of the possible combinations and interactions, let alone test
         | them.
         | 
         | You can search for those that may concern you. Good old search
         | or AI "search".
         | 
         | For example I recently did test the AOT compilation of Clojure
         | (on top of the JVM) code using "Leyden". I used an abandoned
         | Github project as a base but all the JVM parameters related to
         | Leyden had changed names (!) and the procedure had to be
         | adapted. I did it all (as a Dockerfile) in less than an hour
         | with Sonnet 4.6 (complete with downloading/verifying the Leyden
         | JVM, testing, taking notes about the project, testing on
         | different machines, etc.).
         | 
         | These are not trivial calls to the "java" command: it involves
         | a specific JVM and several JVM params that have to work fine
         | together.
         | 
         | The goal was to load 80 000 Clojure/java classes (not my idea:
         | the original project did that part) and see the results: 1.5
         | seconds to launch with the Leyden JVM (and correct params) vs 6
         | seconds for a regular launch (so a 75% gain). GraalVM is even
         | faster but _much_ more complicated /annoying to get right.
         | 
         | It can look overwhelming but I'd say all these parameters are
         | there for a reason and you only need a few of them. But when
         | you need them, you need them.
         | 
         | P.S: unrelated to TFA and as a bonus for the "Java is slow
         | crowd":                   time java -jar hello/hello.jar
         | Hello, World!              real    0m0.040s
         | 
         | And that's without any Leyden/GraalVM trick. For Clojure the
         | "slow" startup times are due to each Clojure function being
         | transformed into one Java .class each and there are _many_
         | Clojure functions. Hence the test with 80 000 Clojure functions
         | from the project I reused: https://github.com/jarppe/clojure-
         | app-startup-time-test (but it's not maintained, won't work as
         | if with the latest Leyden JVM)
        
           | vips7L wrote:
           | I could be missing it because I'm not that familiar with bb,
           | but looking at your repository it doesn't look like you're
           | using any feature that was actually shipped with project
           | Leyden. It looks like you're just using AppCDS which has been
           | around for a long time.
        
           | nromiun wrote:
           | That test does not mean anything. I can also spin up a large
           | LLM on my 5090 and say these models are ready for on device
           | deployment now. However that would not be true for most
           | people. You should test a Golang hello world binary as well.
           | I bet it will take less than 40 milliseconds.
        
         | jmyeet wrote:
         | Wasn't it Joel Spolsky who said every option is a cop out? Or
         | maybe Steve Yegge? I forget. It's something I agree with. I
         | often have this thought when going through the options of
         | something conceptually fairly simple: "who is this for? who
         | actually uses this option?"
         | 
         | I kinda feel the same way with C/C++ warnings. Different code
         | bases decide if different warnings are errors. That was a
         | mistake (IMHO).
         | 
         | The other thought I have scanning these options is how many are
         | related to GC. I kinda think GC is a bit of a false economy.
         | It's just hiding the complexity. I wonder if it would've been
         | better to push GC to be pluggable rather than relying on a host
         | of options, a bit like TCP congestion management. I mean there
         | are /proc parameters for that in Linux, for example, but it's
         | also segregated (eg using BRR).
         | 
         | At the end of the day, none of this really matters. As in, the
         | JVM is mature and I think generally respected.
        
           | vips7L wrote:
           | The GC is pluggable, that's why you have so many to choose
           | from depending on your work load. You rarely if ever have to
           | touch those options. In the last 10 years all of my apps,
           | since I run on a modern version of Java, only ever set max
           | heap size and soon that will (finally) be figured out
           | automatically: https://openjdk.org/jeps/8359211
        
           | izacus wrote:
           | Joe Spolsky also never created anything as popular and widely
           | deployed as Java. It's easy to bloviate about pure software
           | when it doesn't need to literally run the whole world as you
           | know it.
        
             | toyg wrote:
             | Er. IIRC, Spolsky was involved in creating VBA for Excel.
             | Which was arguably orders of magnitude more popular (and
             | still more widely deployed and world-supporting) than Java.
        
               | izacus wrote:
               | In the 90s, as a program manager. And it's a big
               | difference between building an application and a platform
               | (I've done both) when it comes to API design.
        
         | pjmlp wrote:
         | Have you ever seen how many GCC has for plain old C?
        
           | Hendrikto wrote:
           | Yeah, that's a mistake too, and a big reason for why
           | compiling C projects is such a pain.
           | 
           | Notice how I did not compare to C, but modern alternatives.
        
             | pjmlp wrote:
             | Gccgo and tinygo do exist, with enough parameters.
        
             | pron wrote:
             | I'll grant you that Go is extremely opinionated; that's its
             | shtick. But it's an old language that started out with a
             | 1970s design as a statement by its creators against modern
             | programming languages. From its langnauge design, through
             | its compiler, to its GC algorithm, it is intentionally
             | retro (Java retired its Go-like GC five years ago because
             | the algorithm was too antiquated). It may suit your taste
             | and I'm not suggesting that it's bad, but modern it is not.
        
         | layer8 wrote:
         | The comparison with gofmt makes no sense. If Go had myriads of
         | compiler implementations (the analogy being target environments
         | for the JVM) that all had different performance characteristics
         | and other behavioral differences depending on how the source
         | code is formatted, you bet that gofmt would have a lot of
         | options as well.
         | 
         | The JVM is like an operating system. A better comparison would
         | be Linux kernel parameters:
         | https://www.kernel.org/doc/html/latest/admin-guide/kernel-pa...
        
       | guusbosman wrote:
       | There is a 2nd edition now of the Optimizing Java book you are
       | referring to on your site.
        
         | grodriguez100 wrote:
         | He probably knows, since he is one of the authors.
        
       | coolius wrote:
       | This is going to come very handy for development of CodeBrew, my
       | Java IDE for iPhone/iPad. It runs a full OpenJ9 JVM under the
       | hood, and I had to do a bunch off massaging with the options to
       | get it to run properly. I wish I had known this page sooner!
       | 
       | For anyone intered, here's the app:
       | 
       | https://apps.apple.com/app/apple-store/id6475267297?pt=11914...
        
       | rvz wrote:
       | All of that configuration and it will _always_ be less efficient
       | than Rust, or even Golang.
       | 
       | This is why lots of engineers waste time fiddling with options to
       | tune the JVM and still require hundreds of replicated micro-
       | services to "scale" their backends and losing money on AWS and
       | when they will never admit the issue is the technology they have
       | chosen (Java) and why AWS loves their customers using inefficient
       | and expensive technologies.
       | 
       | Even after that, both Go and Rust continue to run rings around
       | the JVM no matter the combination of options.
        
         | cleverfoo wrote:
         | Sure, for a very narrow definition of _efficiency_. There's
         | plenty to complain in terms of the JVM and Java but
         | performance, as in units of work per dollar spent, is not one
         | of them - JITs just have too many opportunities for optimizing
         | generated code.
        
         | deepsun wrote:
         | All of that tooling and Rust will always be less efficient than
         | Assembler.
        
           | metaltyphoon wrote:
           | I... didn't think this makes sense :)
        
             | msla wrote:
             | It makes perfect sense: Rust compilers will never beat a
             | human at scheduling every single opcode perfectly based on
             | the deepest microarchitectural analysis short of decapping
             | the chip and breaking out the ol' electron microscope.
             | Whether it's worthwhile to be that efficient over a whole
             | program, as opposed to a preternaturally tight compute
             | kernel, is definitely questionable.
        
         | fHr wrote:
         | I was a diehard java fanboy but using Rust in the last 5 years
         | more and more I have to agree, but sadly huge Java corporate
         | codebases keep my bills paid still, so I have to deal with it.
         | It is what it is. Also agree the pipeline etc. they love all
         | the waste of the compute in their pocket.
        
           | contraposit wrote:
           | I hope AI will make automated translation of such legacy
           | codebases into any favourite langauge possible in future.
           | Fingers crossed.
        
           | newsoftheday wrote:
           | It sounds like you're not into Java. Perhaps consider
           | switching languages to make room for people who are.
        
           | deepsun wrote:
           | I code on both and they are just for different purposes. E.g.
           | I think it's madness to develop desktop apps in Rust.
           | 
           | Development velocity is way greater in Java.
        
         | arein3 wrote:
         | Yeah doubt that
         | 
         | Recently I had a python friend use the most balls to the wall
         | python backend, he couldnt beleive java was faster, but the
         | numbers werent lying. We did 1 billion iterations of adding a
         | float, took a few seconds in java.
        
         | well_ackshually wrote:
         | That's a nice source, from where up your ass did you find it ?
         | 
         | Go's GC is absolutely awful and leads to nondeterministic
         | pauses and catastrophic latency spikes, especially when the
         | memory pressure and capacity is high. Throw the go GC against a
         | 256GB heap, see how well it survives.
         | 
         | Technologies have strong and weak points. Go's strong points
         | are small, targeted pieces of software and having 66% of a
         | binary basically be if err != nil return err. Rust's strong
         | points are that you get to have the symbol<():soup<_, |_| of {
         | c++ }>> while not saying you're writing c++ and feeling really
         | smug when you say that you only needed to use 5 Arc<Mutex<T>>
         | and rewrote your entire software three times but at least it
         | runs almost as fast as some shitty C that does fgets() in the
         | middle of a hot loop. Java lets you spawn spring boot and
         | instantiate a string through reflection because why not.
         | 
         | I promise you, I can write allocation heavy
         | FizzBuzzEnterpriseFactoryFactories in Rust too.
        
       | motoboi wrote:
       | People say we don't build cathedrals anymore.
       | 
       | But here it is: JVM is a modern cathedral.
        
         | well_ackshually wrote:
         | Multiple generations of builders working together on a grand
         | plan, constantly interrupted by multiple generations of
         | ~~kings~~ multibillion dollar corporations to please add ~~a
         | grand mural remembering his great deeds~~ yet another flag to
         | control exactly the timing of GC pauses because it turns out
         | our server can only do GC between 3 and 3:30 AM.
        
       | exabrial wrote:
       | His other project "Byte Me", along with judicious javap usage,
       | has been super useful for me learning JVM bytecode so I could
       | make a machine learning model compiler for the JVM (basically
       | compile your ML models as native code; ONNX, tree ensembles,
       | regressors, classifiers, etc as native JVM classes with no
       | massive runtime needed)
       | 
       | still in the works, but its here for those interested: Petrify:
       | https://github.com/exabrial/petrify
        
         | deepsun wrote:
         | Why not compiling it to Java source code (not bytecode)? Users
         | would use their own Java compiler then.
         | 
         | Same as, say, ANTLR generates code to parse various texts to
         | AST.
        
       | molticrystal wrote:
       | Chrome has 1496 [0] known options as of today, maybe after a few
       | more pushes they'll catch up to the 1843 of JVM.
       | 
       | An interface like above to sort things would probably be quite
       | helpful as well.
       | 
       | [0] https://peter.sh/experiments/chromium-command-line-switches/
        
         | deepsun wrote:
         | Why not compiling it to Java source code (not bytecode)? Users
         | would use their own Java compiler then.
         | 
         | Same as, say, ANTLR generates code to parse various texts to
         | AST.
        
       | zkmon wrote:
       | Those button at the top link to different domains altogether, but
       | present the same page. So it is one page with multiple domains,
       | instead of one domain with multiple pages.
        
       | scrame wrote:
       | OK, now make them all run at once!
       | 
       | (I know many conflict and there is not a shell buffer long enough
       | to handle all that)
       | 
       | Kidding aside, I actually said "ugh, seriously" when I saw that
       | there were literally thousands of options. Is there a public
       | program with more options?
        
       ___________________________________________________________________
       (page generated 2026-04-12 23:00 UTC)