JRuby isn’t automatically faster than CRuby for every application. A useful comparison keeps the work and correctness checks the same, then measures startup, sustained throughput, latency and memory separately. Otherwise, a result can answer a different question from the one you’re trying to settle.
If you maintain a Ruby service, the decision is practical: will another runtime improve an important operation without introducing an unacceptable compatibility, memory or operating cost? Start there. A short arithmetic loop can reveal something about that loop; it can’t settle a Rails migration.
Write the decision before running the timer
Choose one operation and specify a correct result. For a batch job, that might be the same records transformed and the same output digest. For a service, it might be a completed request with the expected database state. Record failures and retries, not just the number of attempts.
Set the constraints in advance: the available CPU and memory, tolerated latency, runtime lifetime and required dependencies. If the test changes any of them, report the change beside the result. A faster run with twice the resource allowance is a different comparison.
Pin the engine, language compatibility and dependencies
Ruby language compatibility doesn’t make two runtimes identical. JRuby executes on the JVM. Its 10.0 release moved to Ruby 3.4 compatibility and a Java 21 minimum; use the requirements for the exact JRuby release you’re evaluating, rather than treating that historical announcement as a current installation recipe.
Keep a dependency lock and a list of adapters or native extensions that differ between the two configurations. A compatibility failure is a result worth recording. It isn’t a reason to remove an inconvenient part of the workload and keep the same headline.
Give startup and sustained work separate scorecards
Measure a fresh process from launch to a useful result if the application runs short-lived commands. For a long-lived service, also record the progression from startup through repeated work. Keep the early measurements; they tell you what users may experience after a deployment or scale-out.
For the steady-state comparison, decide in advance how you’ll establish a stable measurement window and report the rule. Repeat fresh processes and alternate the order of configurations. That helps expose a result that depends on caches, background activity or one unusually good run.
- Startup: launch-to-ready time and time to the first correct result.
- Steady state: successful work per second and tail latency under a declared load.
- Resources: CPU allocation, observed memory and relevant runtime settings.
- Correctness: output checks, errors, timeouts and retries.
- Repeatability: raw samples, exact commands and a description of the test host.
Time a batch, then check that it did the right thing
Ruby’s monotonic clock is suitable for measuring elapsed time within a process. Use a timer around the operation you intend to compare, not only around its setup. The small example below shows the shape of a checked measurement. The sum is a demonstration, not an application benchmark or a published performance result.
For an actual service comparison, retain a separate load-generation record. A successful timer says nothing about an omitted response, a wrong result or a request that never reached the application.
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = (1..10_000).sum
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
raise 'incorrect output' unless result == 50_005_000
puts "engine=#{RUBY_ENGINE} version=#{RUBY_VERSION} seconds=#{elapsed}"Trace the upstream contribution and evaluate the application separately
Troy Mallory’s builtin-tracking contribution is part of the public JRuby PR 9174 record. That’s a specific engineering contribution with a traceable upstream history. It doesn’t establish a speedup for every Ruby workload.
Our deployment and technical-provenance pages explain that work separately. If your decision concerns a real workload, keep its evaluation equally specific: one question, known configurations and a result another engineer can inspect. The Compute Evaluation Plan is a planning engagement for one workload and up to two configurations, not a completed benchmark or a promised migration outcome.
Sources
- JRuby 10.0.0.0 release requirementsSource published April 14, 2025. Retrieved September 19, 2026.
- Ruby 3.4 Process: clock_gettimePublication date not stated. Retrieved September 19, 2026.
- JRuby PR 9174: builtin tracking contributionPublication date not stated. Retrieved September 19, 2026.
Discuss the work with Valen Systems
Talk through the scope with Valen Systems
A smaller starting point: Plan one workload comparison with a Compute Evaluation Plan