using the commandbox docker image can I specifiy t...
# box-products
r
using the commandbox docker image can I specifiy the JVM memory size in my docker-compose file?
b
@Ryan Albrecht
Copy code
BOX_SERVER_JVM_HEAPSIZE=2g
👍 1
Which is just the generic env var override convention for your
server.json
values
r
mucho gracias!
👍 1
s
is this preferable to JVM args in server.json?
or kinda sorta the same
b
Same
Depends on what makes sense for your deploy
The env vars just get merged into the server.json on start
r
My gut feeling is server,json would be better as that is where most developers would expect that config to be. I only asked because I was playing around with stuff and didnt want to make the file on VPS
s
right now we do something like
Copy code
"jvm":{
        "args" : "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=70 -XX:InitialRAMPercentage=35 -XX:MaxRAMPercentage=90"
    },
in server.json
and use the docker stack file to regulate how much total memory is reserved
just to necro this thread, qq for @bdw429s - I feel like the JVM args here are specifying percentages and ratios while
BOX_SERVER_JVM_HEAPSIZE
is saying 'hey commandbox, use exactly this much as your max heap size' -- this seems like a bit of a philosophical disagreement. given a physical server of RAM constraint X and some number (let's say 1-3) of CFML containers running on it, what's your strategy for provisioning heap sizes? ideally the max of all of them would be greater than the total RAM of the machine on the assumption that not all 3 containers are going to hit max consumption at one time (if indeed the deployment makes that sufficiently unlikely); otherwise you're leaving RAM on the table, yes?
b
@jclausen Do you have any insight on how Ortus tunes our heap sizes with Docker?
j
It kind of depends on the application. I much prefer the newer G1GC collector over parallel and CMS is going away, so I would recommend not using it. I also find the
ReservedCodeCacheSize
is an important one for larger applications with many components. Here’s an example of my defaults for a larger application:
Copy code
-Dfile.encoding=UTF8 -Djava.awt.headless=true -XX:ReservedCodeCacheSize=256m -Xms3072m -Xmx3072m -XX:+UseG1GC
The
MinHeapFreeRatio
is a good one if you are wanting to force GC early. I’ve found that G1GC, though, doesn’t require all of the specific args.
s
I'm trying to avoid hardcoding in specific RAM amounts and just using percentages so we don't have to re-cook our images whenever we change a server configuration (which isn't often, but still)
👍 1
j
Using G1GC, going from a standing stop to full throttle memory isn’t as painful any more so you can usually get rid of
Xms
. With Parallel, you’re going to have to tune it a bit because it will stop application threads while collecting - and you need the extra args to prevent it being too painful. Parallel GC also has diminishing returns in performance as you go above 1GB in heap size.
If you use Java 14, which Commandbox and Lucee will run on, you can use the new Z collector: https://www.baeldung.com/jvm-garbage-collectors#6-z-garbage-collector That will be the default collector, from my understanding in Java 20 and up.
b
Yes, they were talking about ZGC at Devnexus and how it was going to become the default collector.
s
It looks like it can be enabled on Java 11? Idk if I want to jump to Java 14 in production
Just an update to this thread: We tried out ZGC for a week and it was pretty hairy. Production jvm usage spiked to almost everything the container was given and the JVM wouldn't release it. Locally, even with 12 GB of memory allocated, trying to run our test suites would crash the container. Switched to G1GC with String deduplication and everything appears to be fine (though it's only been a few hours). Some reading online suggests that ZGC is better for huge memory apps (like a terabyte) and that Parallel & G1 remain the best 'general purpose, big but not huge memory' app garbage collectors, with the regular disclaimers of YMMV
b
Wow, good to know regarding ZGC. Were you using it in Java 11?
I'm curious how much ZGC itself has changed across versions since introduced 🤔
s
Yes, in 11.
👍 1
b
Let's hope Oracle improved that a bit in later versions!
It's worth noting Lucee 5.3.10 and CommandBox 5.9.0 (which I STILL need to write the release blog for) have preliminary support for Java 17 (YMMV)
Java 17 being the LTS version after 11 and java 21 already being worked on!
s
preliminary like 'should work, just nobody's really used it yet'?
b
More/less. As in works in most of our tests, but there are an infinite number of ways it may not work
s
'there are an infinite number of ways it may not work' is our corporate tagline
👍 1
b
Not blockers, just the way java 16+ works now, you have to add
--add-opens
jvm args for any java modules you are calling via reflection
Oracle did not provide an
--argh-just-make-it-work-like-it-used-to
JVM arg
So every single Java module being accessed via reflection requires an explicit JVM arg per package
s
are you guys planning on going back to Oracle JREs or sticking with adoptopenjdk?
b
And CF uses Java reflection for all access to java methods/classes
Prolly Adopt because it's much easier to package and distribute due to licensing and build availability
👍🏻 1
It's all the "same Java" technhically speaking
Just a matter of who's build you're using of it
While Oracle's penchant for breaking changes is annoying, both CF engines share blame here. Java 8 introduced the invokedynamic stuff for dynamic JVM langauges to avoid reflection, but neither Adobe nor Lucee put any brain cells into fixing what "wasn't broke"
Except, now Oracle is breaking it and it's one of those "well you've had the last 10+ years to refactor away from reflection but you sat on your laurels"
This is the future reckoning those "illegal reflective access will be removed in later versions" console messages have been warning us about since Java 11 (released 5 years ago)
Anywhoo- if you get around to testing on Java 17, here's what you're looking for and how to fix https://ortussolutions.atlassian.net/browse/COMMANDBOX-1587
s
for every module? woof
b
You'll see messages like
Copy code
java.lang.reflect.InaccessibleObjectException: Unable to make public sun.java2d.HeadlessGraphicsEnvironment(java.awt.GraphicsEnvironment) accessible: module java.desktop does not "exports sun.java2d" to unnamed module @45f95ac0
and the fix is to add a JVM arg of
Copy code
--add-exports=java.desktop/sun.java2d=ALL-UNNAMED
Note there are two flavors of the error-- one for opens and one for exports
I'm unclear if this affects random java libraries which do not use Java modules. But every square inch of the JDK has been modularized for certain.
CF has enjoyed the ability for years of just being able to grab the "reflection hammer" from the toolbox to call whatever the heck it wanted for you