ARM64_Lab

Java 8 x64 java -version took 160.3 ms to start

In this article
  1. Look only at commands that start and exit immediately
  2. Where it sits among CLI tools
  3. I almost trusted the “64-Bit” label
  4. Change how it is invoked

The median for java -version was 160.3ms, 9.8x slower than curl --version at 16.3ms measured on the same day.

What caught me was not the slowness itself but the misleading display. java -version prints OpenJDK 64-Bit Server VM, so at a glance you can tell that it is running 64-bit. On ARM64 Windows, however, that 64-bit label does not necessarily mean ARM64-native. It needs a separate check. Reading the PE header showed Machine as 0x8664, which is x64. That was when I realized the display alone was not enough.

I was using Eclipse Adoptium jdk-8.0.492.9-hotspot. The path was C:\Program Files\Eclipse Adoptium\jdk-8.0.492.9-hotspot\bin\java.exe, and on the Surface Pro 11th Edition's ARM64 Windows it starts on the emulation side. I measured it on June 27, 2026, and treated the date in the record as 2026-06-27. The SoC was a Snapdragon X 12-core X1E80100 @ 3.40GHz, with 32GB of memory, running the ARM64 edition of Windows 11 Pro 10.0.26200. The machine was connected to AC power, with the default Balanced power plan unchanged.

Look only at commands that start and exit immediately

This measured process startup-to-exit time, not application processing performance. I was initially suspicious of cases that invoke short tools repeatedly, so I ran each tool's short command five times: java -version for Java, curl --version for curl, and python -c pass for Python.

1..5 | ForEach-Object {
    (Measure-Command { java -version }).TotalMilliseconds
}

I read the PE header in the same workflow. The field of interest is Machine: ARM64 is 0xaa64, and x64 is 0x8664. Rather than trust the text from java -version, I inspected the executable itself. If I had skipped this, I probably would have finished with the wrong assumption.

$bytes = [System.IO.File]::ReadAllBytes($path)
$peOffset = [BitConverter]::ToInt32($bytes, 0x3c)
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)

I still had not found an ARM64 Windows build of JDK 8 locally. I needed to run a tool that assumes old Java 8, so I did not upgrade the JDK that day. JDK 17 or later might offer another option, but the goal that day was to run an old-Java-8-dependent tool, so I checked the actual java.exe first.

Where it sits among CLI tools

I am leaving all five values here. By median, curl was fastest at 16.3ms, followed by Python at 36.3ms, Git at 70.0ms, and Node.js at 86.1ms. Java was 160.3ms, in a different part of the table from the light ARM64-native CLIs.

Tool PE architecture Median All 5 runs
curl --version ARM64 16.3ms 87.3 / 16.3 / 18.6 / 16.3 / 15.5
python -c pass ARM64 36.3ms 43.4 / 33.9 / 36.3 / 38.2 / 35.7
git --version ARM64 70.0ms 80.6 / 57.0 / 70.0 / 82.6 / 67.0
node -e 0 ARM64 86.1ms 93.7 / 76.2 / 93.1 / 86.1 / 80.8
java -version x64 160.3ms 157.3 / 154.6 / 160.3 / 188.0 / 187.1
powershell -NoProfile -c exit ARM64 192.5ms 219.7 / 731.6 / 177.5 / 178.0 / 192.5
pwsh -NoProfile -c exit ARM64 289.6ms 289.6 / 274.9 / 337.8 / 274.6 / 365.6

The first curl run jumped to 87.3ms. Looking only at that initial value would pull the story in another direction, but the remaining runs were between 15.5ms and 18.6ms, so it may have picked up first-use file-cache or surrounding variation. Java also ranged from 154.6ms to 188.0ms, but it did not show the same one-time step as curl.

I covered the PowerShell variants in another article, so they are supporting characters here. They show where Java's 160.3ms sits: faster than Windows PowerShell 5.1 at 192.5ms and faster than pwsh at 289.6ms. With repeated short CLI calls, though, the gap from curl or Python accumulates.

I almost trusted the “64-Bit” label

Honestly, the OpenJDK 64-Bit Server VM display initially made me feel a little reassured. It is easy to think that 64-bit is all that matters. That was the unexpected part: I had not considered that a 64-bit display might not be reassuring. In this case, 64-Bit Server VM means 64-bit x64, not ARM64-native. The wording is quite confusing.

Getting this wrong also changes how you interpret the measurements. It is tempting to see only the 160.3ms for java -version and immediately say “it is slow because of emulation.” But JVM startup also has inherently expensive work, so the display, PE header, and measured time must be considered separately. Since the PE is x64, the suspicion is reasonable, but it is not a complete explanation.

This measurement alone cannot establish causality. It would be too easy to collapse the fact that it is x64 and the weight of JVM startup into one explanation. The JVM starts the runtime and goes through class-loader and VM initialization. How much of the 160.3ms is tied to the Java 8 x64 executable, and how much is ordinary JVM startup? That requires installing an ARM64 JDK 17, for example, and measuring under the same conditions.

My failure here was wanting to rush to a conclusion. The PE header establishes that it is x64, and the five measurements establish that it is slow relative to these CLIs. They do not establish that “x64 made it 160.3ms.” I am keeping those statements separate.

Change how it is invoked

In actual use, I removed Java-based tools from automations that start a new process for every invocation. At 160.3ms, one call is tolerable, and a person running it manually may not care. The problem is a design that invokes short work in small pieces repeatedly. That is where the short waits accumulate.

For example, if a small conversion or check starts a separate java process for every file, startup time becomes more visible than the work itself. I avoid that shape in automation where possible, use a resident process, or move the small operation to a light ARM64-native CLI such as Python or curl. That is the invocation pattern I changed after seeing the numbers.

If there is a reason to stay on JDK 8, the choices are quite limited locally. I could not find an ARM64 Windows build, so x64 was the practical option. For tools that can move to a newer version, it is worth measuring again with an ARM64 JDK.

What this established is limited: even the minimal java -version took 160.3ms, and that java.exe was x64. Next I would install ARM64 JDK 17 on the same Surface Pro and repeat the five-run measurement to separate JVM startup itself from emulation. That is left for another time.

Benchmark Emulation
a
arm64lab — Independent publisher

Personal test notes from a Surface Pro 11th Edition with Snapdragon X Elite, used as a daily machine since May 2025. Results are based on direct measurements and do not represent any company or organization.