Repository navigation
Faster starts, a real image-mode JDK, warm library VMs, child processes, file watching, large files, less memory per VM, and compatibility fixes.
Upgrading
- The JDK now ships as one file,
jdk/image.jar, in place ofjdk/<module>.jarandjdk/jdk.localedata.txt. A page that servesdist/needs no change, but the server must still answer Range requests, now forjdk/image.jar. - The
java-webcommand now runsdist/cli.js.dist/node.jsand its exports are unchanged. - Node keeps boot snapshots in
~/.cache/java-web/snapshots(up to 16). SetJAVA_WEB_SNAPSHOT_DIRto move it, or to an empty value to turn snapshots off.
New
- Child processes under Node:
ProcessBuilder,Runtime.execandProcessHandlestart and manage the host's programs, with pipes, pipelines, redirects, environment and working directories as on HotSpot. Startingjavastarts another java-web VM on the same image. (#45) WatchServicereports files created, changed and deleted inside the VM. (#46)- Files of any size: a file streams to the host once it passes 4 MiB instead of living in memory, so multi-GB files work under Node. A 256 MiB write and read went from 829 MB and 36 s to 338 MB and 2.9 s. (#47)
- Warm snapshots, opt-in with
warmSnapshot: true(startLibraryunder Node,cheerpjInitin the browser): a library VM is saved again once its calls have warmed it up, so a later start skips javac's cold start. A first javac compile takes about a fifth of the time under Node and half in Chromium. The image also keeps the JIT's generated code, which makes the first call after a restore about 20% faster still. (#48, #58, #59) cheerpjInit({ maxHeap: "256m" })caps the whole Java heap in the browser, as-Xmxdoes under Node: a program that fills it getsOutOfMemoryError: Java heap spaceinstead of the tab dying. (#57)cheerpjInit({ debug: true })logs VM events to the console, such as whether a warm snapshot was saved or restored. (#52)jdk.managementis in the image:com.sun.management.UnixOperatingSystemMXBean(open and maximum descriptor counts) andHotSpotDiagnosticMXBean.getVMOption. (#61)- Symbolic and hard links on host file systems,
SecureDirectoryStream, and new files and directories created with the requested mode less the umask. (#61) Deflatercompresses: zlib's levels, strategies, flush modes and dictionaries. Level 6 output is within 0.1% of zlib's size, and a jar of 1,439 classes comes out 54% smaller. (#63)ThreadMXBeanthread info, thread dumps with locked monitors and synchronizers, and deadlock detection for monitors andjava.util.concurrentlocks, with no cost tosynchronizedorReentrantLock. (#65)- Virtual threads no longer pin their carrier when they block on a monitor or wait in
Object.wait, as in JDK 24 and later. (#68) - Launcher options:
-mand--module,-Xbootclasspath/a(directories and jars, repeatable) and--patch-modulefor boot modules.bin/javaexists in the image, andkill -QUITprints a thread dump. (#69) jdk.netandjdk.nio.mapmodeare in the image. ATZvalue that is a POSIX rule, such asMEZ-1MESZ,M3.5.0,M10.5.0/3, sets the default time zone's offset and daylight saving dates. Memory pools and managers have G1's names, as HotSpot's default collector reports them. (#69)
Faster
- Boot snapshots: a VM starts from the state saved after an earlier boot with the same inputs. Hello world under Node goes from about 2.3 s to under 0.5 s. In the browser, later runs on a page start in about 0.3 s. (#29)
- Image-mode JDK: the JDK is a jlinked
lib/modules, as a normal JDK has, instead of an exploded tree. A full boot under Node drops from 1.9 s to 1.3 s, andjrt:/no longer walks every file of the image. (#37) - javac's first compile is about 40% faster in Node (10.3 s to 6.0 s from a snapshot) and in the browser (6.2 s to 3.7 s on a cold page). (#34, #37)
- Browser downloads: one request per app class instead of two, a smaller boot index, and the image ranges a start and javac read packed into
boot.packandjdk/javac.pack. (#30, #31, #37) - Node's compile cache for the
java-webcommand, cheaper calls between compiled and interpreted code, and intrinsics for SHA, AES, BigInteger,Math.multiplyHighand P-256 (EC work about 44% faster). (#20, #21, #26, #27, #28, #33) - Less heap per VM: UTF-8 constants are plain strings, parsed member records are dropped after linking, and the constant pool lives in typed arrays. Each saves a few MB; the constant pool change alone takes about 8 MB off a library VM after a javac compile. (#41, #55, #60)
- Unmapping a file gives its memory back. (#56)
- Zip reading and writing: faster inflate and CRC32, native array compare and hash code (which also speeds up
Arrays.equals,Arrays.mismatchandString.hashCode), and calls that see one receiver class are inlined. A 12 MB deflated zipfs entry writes and verifies in 449 ms instead of 1,154 ms. (#62) - Uncontended
synchronizedis 12 to 38% faster, and contended monitors between platform threads about 30% faster. (#68) - Startup and memory: class file parts are decoded on first use, line tables point into the class bytes, and generated code is smaller. About 21% less heap after a javac compile (101 to 80 MB), and hello world from a boot snapshot about 13% faster. Snapshots from older builds are rebuilt once. (#70)
Fixes
- Class initialization, exception handlers and bytecode edge cases now match HotSpot. (#22, #25)
- Files: writes the host refuses are reported, a new file the host refuses reports the host's reason, renaming a file over a directory is refused, and special characters in browser file paths are kept. (#19, #23, #24, #35)
- Modification times set to the nanosecond read back exactly. (#38)
FileStoreandFile.getTotalSpace(),getFreeSpace()andgetUsableSpace()report the host file system's figures, and direct I/O (ExtendedOpenOption.DIRECT) works. (#42)java.util.prefsstores preferences: the file natives behindPreferences.userRoot()are implemented. (#43)- A process that upgrades the package in place keeps each running VM on the image it started with. (#39)
- The
java-webcommand no longer hangs at exit on some x64 hosts after a program used several hundred MB. (#44) - A
RandomAccessFileopened read-only refuses writes, as on HotSpot. (#47) - A thread that joins the main thread no longer deadlocks when main ends, for example with an uncaught exception. (#49)
- Under Node,
-Xmxcaps the whole heap: a program that fills it getsOutOfMemoryError: Java heap space, which it can catch, instead of being killed. Before, it only capped a single array. (#50, #53) - Writing far past the end of a file, as sparse files do, no longer allocates the gap, so multi-GB files work. Append mode follows
O_APPEND, and a directory can be opened read-only as a channel. (#54) - A file mapping that does not fit fails with
IOException: Map failed, as on HotSpot, instead of crashing. (#56) - A warm or boot snapshot of a deep object graph (a long linked list, for example) no longer overflows the stack while saving or restoring. Older snapshot files are ignored and rebuilt. (#59)
- An open file keeps its inode number after its path is deleted, child programs are found on the parent's
PATH, and an unreadable file fails withEACCES. (#61) jrt:/reads class files, and stack frames carry module versions as on HotSpot. (#37)Runtimereports real heap figures. (#26)- A VM that hits an internal error on its main thread exits with status 1 instead of hanging. (#29)
park,Object.waitandThread.sleepwith a timeout longer than about 24 days, such asLockSupport.parkNanos(Long.MAX_VALUE), no longer wake after 1 ms and spin. (#66)-XX:OnOutOfMemoryErrorruns its commands and-XX:MaxDirectMemorySizelimits direct buffers, as on HotSpot.java -versionworks. (#67)- File access times are kept and reported: reading a host file no longer changes its access time, and setting times on a symlink with
NOFOLLOW_LINKSchanges only the link. (#67) WatchServicesees changes other processes make in a watched host directory, and no longer hangs when a watched directory is deleted during registration or crashes on a long event queue. (#67, #72)- Sockets: a socket reports writable after
shutdownOutput, a connected datagram socket can connect again, Unix domain sockets bind the unnamed address and long paths, and an accepted Unix socket reports its client's name. (#69) - Processes: a child's output is read in full before the VM hears it exited, merged output included; the
PATHsearch and exec errors follow the JDK's; an unlimited open file limit reports -1. (#69, #72) - A stack overflow inside an overflow handler throws a bare
StackOverflowErrorinstead of failing the VM. TheConstantPoolnatives check their index and entry kind. (#69) Deflater.setDictionaryin the middle of a raw stream no longer drops input it had taken but not yet written. (#72)- An open file shares bytes with another open of the same path only when they are the same file, so reopening a replaced symlink target reads the new file. (#72)
- An
OutOfMemoryErroris thrown even when the hook that reports it fails, and-XX:OnOutOfMemoryErrorcommands run even when their header cannot be written. (#72)
Tests
CI now runs about 4,000 of OpenJDK's own regression tests (up from 2,524 in 0.1.1), split into eight shards balanced by run time, from the built bundle, and retries rate-limited framework downloads. The test runner evaluates @requires as jtreg does, expands jtreg's variables in @run lines, puts @library directories on test.src.path, and supports @clean, @run driver and @run build. Tests that need other locales run with locale data. (#32, #36, #40, #42, #43, #44, #45, #46, #47, #49, #50, #51, #54, #56, #61, #65, #67, #68, #69, #71). Pull requests run the test directories their changes can affect plus a sample of the rest. (#72)
Known limits
- Child processes need Node; the browser still cannot start them. A child cannot use a directory that exists only in the VM, such as
/jdk, as its working directory. - In the browser,
maxHeapcounts arrays of 4 KB or more; a program that allocates only small objects is not capped. Only Chromium has been tested. - File mappings are copies in the VM's 512 MB native memory.
- Closing
System.outorSystem.errdoes not close the host stream. ASecureDirectoryStreamfollows its directory's path, not the directory itself.
Full Changelog: v0.1.1...v0.1.2