JVM Configuration
PAL runs as a standard Java process launched by the bin/pal script. PAL requires Java 17 or later. The script sets sensible defaults for heap sizing, garbage collection, and module exports, on top of a baseline of JVM module exports required for PAL to function. Three layers of customization let you tune JVM behavior.
Precedence
JVM options are assembled in this order. Later layers override earlier ones (last wins):
- Baseline JVM module exports —
--add-exportsand--add-opensdirectives required by AspectJ weaving, Chronicle Queue, and reflection-based dispatch. Always applied; not user-configurable. - Category environment variables — replaceable defaults for heap, GC, and JMX (
pal runonly). pal.vmoptionsfile — persistent per-installation configuration.PAL_JAVA_OPTSenvironment variable — one-off overrides, always wins.
Category Environment Variables
These variables apply only to the pal run command (peer processes). Setting a variable replaces its default entirely, giving full control over that category without affecting others.
PAL_HEAP_OPTS
Heap sizing options. Default: -Xmx1g
# Increase heap to 4 GB with a 2 GB initial size
export PAL_HEAP_OPTS="-Xmx4g -Xms2g"
pal run -cp app.jar com.example.Main
PAL_GC_OPTS
Garbage collector selection and tuning. Default:
# Switch to ZGC for low-latency workloads
export PAL_GC_OPTS="-XX:+UseZGC -XX:+ZGenerational"
pal run -cp app.jar com.example.Main
PAL_JMX_OPTS
JMX remote monitoring configuration. Default: built automatically from PAL_JMX_HOST and PAL_JMX_PORT if both are set, otherwise empty.
!!! warning "Insecure default"
The auto-built JMX profile sets com.sun.management.jmxremote.authenticate=false and com.sun.management.jmxremote.ssl=false, with local.only=true. This is convenient for local debugging but must not be exposed to untrusted networks. For production, set PAL_JMX_OPTS directly with authentication and TLS as shown below.
# Enable JMX with convenience variables (builds PAL_JMX_OPTS for you — local-only, no auth/TLS)
export PAL_JMX_HOST=localhost
export PAL_JMX_PORT=9999
pal run -cp app.jar com.example.Main
# Production: set the full JMX configuration directly with authentication and TLS
export PAL_JMX_OPTS="-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.ssl=true \
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password"
pal run -cp app.jar com.example.Main
Setting PAL_JMX_OPTS directly takes precedence over PAL_JMX_HOST/PAL_JMX_PORT.
pal.vmoptions File
For persistent JVM configuration that doesn't require environment variables, create a pal.vmoptions file in the PAL config directory:
The file contains one JVM option per line. Blank lines and lines starting with # are ignored.
# config/pal.vmoptions
# Heap
-Xmx4g
-Xms2g
# Remote debugging (suspend=n means don't wait for debugger)
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
# Application properties
-Dmy.config.path=/etc/pal/app.properties
An example file with all defaults commented out ships at $PAL_HOME/config/pal.vmoptions.example. Copy it to $PAL_HOME/config/pal.vmoptions and uncomment the options you need.
Options in this file are loaded after the category environment variables and before PAL_JAVA_OPTS, so they can override category defaults but are themselves overridden by PAL_JAVA_OPTS.
PAL_JAVA_OPTS Environment Variable
A catch-all for any JVM flags, system properties, or agent options. Appended last, so it always takes precedence.
# Add a system property for a single run
PAL_JAVA_OPTS="-Dmy.feature.enabled=true" pal run -cp app.jar com.example.Main
# Attach a profiling agent
PAL_JAVA_OPTS="-agentpath:/opt/async-profiler/lib/libasyncProfiler.so=start,file=profile.jfr" \
pal run -cp app.jar com.example.Main
# Enable remote debugging
PAL_JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005" \
pal run -cp app.jar com.example.Main
Common Scenarios
Production: increase heap and tune GC
export PAL_HEAP_OPTS="-Xmx8g -Xms8g"
export PAL_GC_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=16m"
pal run -d prod-etcd:2379 -k prod-kafka:9092 --wal my-wal -cp app.jar com.example.Main
Low-latency: switch to ZGC
export PAL_GC_OPTS="-XX:+UseZGC -XX:+ZGenerational"
export PAL_HEAP_OPTS="-Xmx4g"
pal run -cp app.jar com.example.Main
Debugging: attach a debugger
PAL_JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005" \
pal run -cp app.jar com.example.Main
Then connect from your IDE to localhost:5005.
Reference: Environment Variable Summary
This table covers the env vars read by the bin/pal launch script. For peer behavior and CLI flag env vars — PAL_DIRECTORY, PAL_PROPERTIES, PAL_KAFKA_SERVERS, PAL_CALLBACK_TIMEOUT_MS, and many others — see CLI Reference → Environment Variables. Those influence what the peer does at runtime, not how the JVM is launched.
| Variable | Scope | Default | Description |
|---|---|---|---|
PAL_HEAP_OPTS |
pal run |
-Xmx1g |
Heap sizing flags |
PAL_GC_OPTS |
pal run |
G1GC, 200ms pause | GC selection and tuning |
PAL_JMX_OPTS |
pal run |
From PAL_JMX_HOST/PORT |
Full JMX configuration (insecure auto-built default — see PAL_JMX_OPTS) |
PAL_JMX_HOST |
pal run |
(unset) | JMX hostname. Read by both the launch script and the peer (advertised in the directory) |
PAL_JMX_PORT |
pal run |
(unset) | JMX port. Read by both the launch script and the peer (advertised in the directory) |
PAL_JAVA_OPTS |
all commands | (empty) | Catch-all, appended last |
JAVA_AGENT |
all commands | (unset) | Java agent JAR path (added as -javaagent:<path>) |
PAL_PEER_LOGGING_CONFIG |
all commands | (unset) | PAL peer Logback config file (exported as -Dpeer.logging to every JVM the script launches) |
PAL_CLI_LOGGING_CONFIG |
all commands | (unset) | PAL CLI Logback config file (exported as -Dcli.logging to every JVM the script launches) |
Logging Configuration
PAL uses shaded Logback for its own internal logging, so it never interferes with your application's logging — even if your application also uses SLF4J and Logback. The two logging systems are completely independent.
PAL's logging is controlled by two XML configuration files:
| File | Controls | Environment Variable |
|---|---|---|
peer-logging.xml |
pal run (peer runtime) |
PAL_PEER_LOGGING_CONFIG |
cli-logging.xml |
CLI commands (pal log print, pal call, etc.) |
PAL_CLI_LOGGING_CONFIG |
Both files are generated by pal init into the config/ directory and wired up in .env.pal. If neither environment variable is set, PAL falls back to built-in defaults that write to STDOUT at ERROR level (peer) and WARN level (CLI). Configure the environment variables to capture richer output or route it to files.
Because PAL uses shaded Logback, configuration files must use PAL's appender classes (io.quasient.pal.common.logging.PeerFileAppender, io.quasient.pal.common.logging.PeerConsoleAppender) and PAL's logger namespaces (e.g., io.quasient.pal, io.quasient.pal.shd.apache.kafka). See config/peer-logging.xml.example and config/cli-logging.xml.example for the full structure.