The PostgreSQL configuration variable pljava.vmoptions
can be used to
supply custom options to the Java VM when it is started. Several of these
options are likely to be worth setting.
If using the OpenJ9 JVM, be sure to look also at the VM options specific to OpenJ9.
By default, a small set of Java modules (including java.base
,
org.postgresql.pljava
, and java.sql
and its transitive dependencies,
which include java.xml
) will be readable to any Java code installed with
install_jar
.
While those modules may be enough for many uses, other modules are easily added
using --add-modules
within pljava.vmoptions
. For example,
--add-modules=java.net.http,java.rmi
would make the HTTP Client and WebSocket
APIs readable, along with the Remote Method Invocation API.
For convenience, the module java.se
simply transitively requires all the
modules that make up the full Java SE API, so --add-modules=java.se
will make
that full API available to PL/Java code without further thought. The cost,
however, may be that PL/Java uses more memory and starts more slowly than if
only a few needed modules were named.
Third-party modular code can be made available by adding the modular jars
to pljava.module_path
(see configuration variables)
and naming those modules in --add-modules
. PL/Java currently treats all jars
loaded with install_jar
as unnamed-module, legacy classpath code.
For more, see PL/Java and the Java Platform Module System.
PL/Java is free of byte-order issues except when using its features for building user-defined types in Java. At sites with no current or planned use of those features, this section does not require attention.
The 1.5.0 release of PL/Java begins a transition affecting the byte-order defaults, which will be completed in a future release. No immediate action is recommended; there is a byte-order page for more on the topic and an advance notice of an expected future migration step.
Class data sharing is a commonly-supported Java virtual machine feature that reduces both VM startup time and memory footprint by having many of Java's runtime classes preprocessed into a file that can be quickly memory-mapped into the process at Java startup, and shared if there are multiple processes running Java VMs.
How to set it up differs depending on the Java VM in use, Hotspot (in Oracle Java or OpenJDK with Hotspot), or OpenJ9 (an alternate JVM also available with OpenJDK). The instructions on this page are specific to Hotspot. For the corresponding feature in OpenJ9, which is worth a good look, see the class sharing in OpenJ9 page.
For Hotspot, the class data sharing is enabled by including
-Xshare:on
or -Xshare:auto
in the pljava.vmoptions
string. In rough terms in 64-bit Java 8 it can
reduce the ‘Metaspace’ size per PL/Java backend by slightly over 4 MB, and
cut about 15 percent from the PL/Java startup time per process.
Sharing may be enabled automatically if the Java VM runs in client
mode
(described below), but may need to be turned on with -Xshare:on
or
-Xshare=auto
if the VM runs in server
mode.
The on
setting can be useful for quickly confirming that sharing works,
as it will report a hard failure if anything is amiss. However, auto
is
recommended in production: on an operating system with address-space layout
randomization, it is possible for some backends to (randomly) fail to map
the share. Under the auto
setting, they will proceed without sharing (and
with higher resource usage, which may not be ideal), where with the on
setting they would simply fail.
Note: the earliest documentation on class data sharing, dating to Java 1.5, suggested that the feature was not available at all in server mode. In recent VMs that is no longer the case, but it does have to be turned on.
To confirm that sharing is on, look at PL/Java's startup message for a line similar to:
Java HotSpot(TM) 64-Bit Server VM (25.74-b02, mixed mode, sharing)
To see the startup message after PL/Java is already installed, use
SET client_min_messages TO debug1;
in a new session, before executing any PL/Java function;
SELECT sqlj.get_classpath('public');
for example.
classes.jsa
not presentIf the option -Xshare:on
makes PL/Java fail to start, with a message like
An error has occurred while processing the shared archive file.
Specified shared archive not found.
then the classes.jsa
file was not automatically created when Java was
installed. It can be created with the simple command java -Xshare:dump
(run with adequate privilege to write in Java's installed location).
In Hotspot, the basic class data sharing feature includes only Java's own runtime classes in the shared archive. When using Java 8 from Oracle, 8u40 or later, or OpenJDK with Hotspot starting with Java 10, an expanded feature called application class data sharing is available, with which you can build a shared archive that preloads PL/Java's classes as well as Java's own. In rough terms this doubles the improvement in startup time seen with basic class data sharing alone, for a total improvement (compared to no sharing) of 30 to 35 percent. It also allows the memory per backend to be even further scaled back, as discussed under “plausible settings” below.
(In OpenJ9, the basic class sharing feature since Java 8 already includes this ability, with no additional setup steps needed.)
Basic class data sharing is widely available with no restriction, but
application class data sharing in Oracle Java is a
“commercial feature” that first appeared in
Oracle Java 8. It will not work unless pljava.vmoptions
also contain
-XX:+UnlockCommercialFeatures
, with implications described in the
“supplemental license terms” of the Oracle
binary code license for Java SE. The license seems
to impose no burden on use for internal development and testing, but requires
negotiating an additional agreement with Oracle if the feature will be used
“in your internal business operations or for any commercial or production
purpose.” It is available to consider for any application where the
additional performance margin can be given a price.
In OpenJDK (with Hotspot), starting in Java 10, the same feature
is available and set up in the same way, but is freely usable; it does not
require any additional license, and does not require any
-XX:+UnlockCommercialFeatures
to be added to the options.
Starting in Java 11, Oracle offers
Oracle-branded downloads of both “Oracle JDK” and “Oracle's OpenJDK builds”
that are “functionally identical aside from some cosmetic and packaging
differences”. “Oracle's OpenJDK builds” may be used for production or
commercial purposes with no additional licensing, while any such use of
“Oracle JDK” requires a commercial license. The application class data sharing
feature is available in both, and no longer requires the
-XX:+UnlockCommercialFeatures
in either case (not in “Oracle's OpenJDK builds”
because their use is unrestricted, and not in “Oracle JDK” because the
“commercial feature” is now, effectively, the entire JDK).
In OpenJDK (with OpenJ9), the class-sharing feature present from Java 8 onward will naturally share PL/Java's classes as well as the Java runtime's, with no additional setup steps.
Here are the instructions for setting up application class data sharing in Hotspot.
Here are instructions for setting up class sharing (including application classes!) in OpenJ9.
-XX:AOTLibrary=
JDK 9 and later have included a tool, jaotc
, that does ahead-of-time
compilation of class files to native code, producing a shared-object file
that can be named with the -XX:AOTLibrary
option. Options to the jaotc
command can specify which jars, modules, individual classes, or individual
methods to compile and include. Optionally, jaotc
can include additional
metadata with the compiled code (at the cost of a slightly larger file),
so that the Java runtime's tiered JIT compiler can still further optimize
the compiled-in-advance methods that turn out to be hot spots.
To make a library of manageable size, a list of touched classes and methods from a sample run can be made, much as described above for application class data sharing.
A blog post by Matthew Gilliard reports successfully combining jaotc
compilation and application class data sharing with good results, and goes into
some detail on the preparation steps.
-XX:+DisableAttachMechanism
Management and monitoring tools like jvisualvm
(included with the Oracle JDK)
can show basic information about any running Java process, but can show much
more detailed information by ‘attaching’ to the process.
By default, attachment requires the tool to be run on the same host as the
database server, and under the same identity. Those existing restrictions
should satisfy most security requirements (after all, a local process under
the postgres identity has many other ways to bypass PostgreSQL's assurances),
but there can also be non-security-related reasons to add the
-XX:+DisableAttachMechanism
option:
jvisualvm
, it is possible for
jvisualvm
to hang after selecting a Java process to display, if that VM
has class data sharing enabled. In such cases, adding
-XX:+DisableAttachMechanism
to the VM options will ensure that jvisualvm
can at least display the usual overview information that is available when
it cannot attach.-XX:+DisableAttachMechanism
seems to
reduce the necessary MetaspaceSize
by about 3 megabytes.client
and server
VMA Java VM may be able to operate in a client
mode (optimized for starting
small apps with minimal latency), or a server
mode, tailored to large,
long-running apps emphasizing throughput. Typically the server
mode is
selected automatically if a ‘server class’ (large memory or 64-bit) platform
is detected.
PostgreSQL will often be run on ‘server class’ platforms, causing the VM to
select server
mode, when the usage pattern in PL/Java more closely resembles
the client
scenario.
While there is no one simple option to force client
mode if the VM has
selected server
, it is possible to adjust individual settings to more
appropriate values.
The heap size settings are important, because the defaults on a server-class
machine will be to grab a substantial fraction of all memory. In a PL/Java
application where many processes may run, it is more important to choose
smaller heap sizes close to what is actually needed. The size can be set
with -Xms
to give a starting size, which the VM can expand if needed; this
is a safe option when you have an idea what the usual case memory demand will
be, but are not confident about the maximum that could sometimes be needed.
A hard limit can be set with -Xmx
if you know a heap size that your code
should never need to exceed.
The choice of garbage collector can also affect the memory
footprint, as the different collectors incur different memory overheads.
If it performs adequately for the application, the Serial
collector
seems to lead the choices in space efficiency, followed by ConcMarkSweep
.
The G1
collector, favored as ConcMarkSweep
's replacement, uses slightly
more space to work, while Parallel
and ParallelOld
will occupy more than
double the space of any of these.
The optimal memory settings and garbage collector for a specific PL/Java application are best determined by testing, but it can be helpful to have an idea what is realistic. Java's default heap and metaspace sizes, especially on a server-class machine, tend to be far larger than necessary.
As a point of reference, PL/Java can load, and execute the tests in, its
shipped pljava-examples
jar with the following settings:
-Xshare:on -XX:+DisableAttachMechanism -Xms2m -XX:+UseSerialGC
and end up with a heap grown to slightly under 4 MB, and a 5 MB metaspace
with less than 2 MB used. (The only way to get a metaspace smaller than 5 MB
is to use the -XX:MaxMetaspaceSize
option, which is a hard limit, with the
risk of out-of-memory errors if set too low. The test described here can be
completed with the metaspace limited to 3 MB.)
If the Oracle application class data sharing feature is enabled, the metaspace limit can be set at 2 MB, and conclude the test without growing past 1 MB.
For an application where startup time is most critical (for example, only
trivial work is being done in Java, but needed in many short-lived
backend sessions), a few percent can be saved by setting the initial heap size
slightly larger than the smallest that works, to avoid an initial garbage
collection. In a test using PL/Java to do trivial work (nothing but
SELECT sqlj.get_classpath('public')
), the sweet spot comes around
-Xms5m
(which seems to end up allocating 6, but completes
with no GC in my testing).
Between releases of this documentation, breaking news, tips, and metrics on PL/Java performance tuning may be shared on the performance-tuning wiki page.