Ruby 2.1
State of JRuby 2014
Summarized using AI

State of JRuby 2014

by Hiro Asari

In the talk "State of JRuby 2014" presented by Hiro Asari at RubyConf AU 2014, the speaker discusses the current state and future of JRuby, highlighting its advantages and upcoming features. JRuby is a Ruby language implementation on the Java Virtual Machine (JVM) that offers several benefits compared to the standard Ruby implementation (MRI). Throughout the presentation, key points include:

  • Performance Comparisons: JRuby can utilize multiple cores due to its thread management, unlike MRI's global interpreter lock (GIL) which can limit performance on multi-core machines. The JVM's mature garbage collectors also contribute to better performance for memory-intensive tasks.
  • Web Server Options: For Rails developers, JRuby offers various web server options such as TorqueBox, Puma, and Trinidad, which can provide integrated services that optimize deployments.
  • Benchmarks and Performance Gains: The presenter cites several benchmarks demonstrating that JRuby generally outperforms Ruby 2.0 in tasks like JSON serialization and database queries. These improvements are attributed to both JRuby and the TorqueBox framework.
  • History and Development: JRuby has evolved since its inception in 2001, gaining significant features like C extension support and invoke dynamic support in the subsequent versions. The transition to JRuby 9000 aims to bring compatibility with Ruby 2.1 and improve overall performance through architectural updates, including a new intermediate representation (IR) and the experimental Truffle compiler.
  • Addressing Startup Times: One of JRuby’s significant pain points is slow startup times. Optimizations such as Nailgun and Drip are introduced to mitigate these issues, enhancing execution speed by maintaining a warm JVM instance.
  • Future Directions: Looking forward, JRuby will continue to evolve with improvements in performance metrics as the JVM updates. Community involvement is encouraged through Google Summer of Code mentorship opportunities.

The main takeaway is that JRuby is not only a viable alternative to MRI but shows promise for substantial performance gains with ongoing development and optimizations, making it worthy of consideration for Ruby developers looking for performance improvements in their applications.

00:00:07.120 Thank you for having me, Australia. This is my third time here, and I really love it. You guys have awesome weather and great beers, especially in New Zealand. Today, I'm going to talk about what JRuby was last year and what is coming this year.
00:00:24.000 Have you heard of JRuby? Great! Have you tried JRuby? I would like to convince you that JRuby is worth a try. There are major pain points that might be keeping you from trying or using JRuby right now, and I will present some ways to mitigate these issues.
00:00:32.640 Before going over those points, I would like to remind you that JRuby is an implementation of the Ruby language. At the end of the day, JRuby aims to be just Ruby for you. However, there are differences, and I don't want to position the two implementations as rivals, as these differences can work to your advantage.
00:00:41.160 Some things are fundamentally different, and there are no ways of getting around these differences, particularly when it comes to threads. In the days of Ruby 1.8, there was only one thread for the Ruby interpreter, and the threads implemented by the Ruby runtime were essentially just one single thread on the OS side.
00:01:03.920 In Ruby 1.9 and 2.0, things improved slightly; the Ruby interpreter can now use more than one OS thread. However, there is a global interpreter lock (GIL) that prevents those threads from running concurrently. If you have a very busy Ruby process, you will see only one core being busy at all times, even if you have multi-core machines.
00:01:22.640 In contrast, JRuby threads are backed by OS threads, so you can utilize many cores at once. This is one possible reason to consider JRuby instead of MRI for your application.
00:01:38.360 I want to emphasize that JRuby is a fast implementation of the Ruby language on the Java Virtual Machine (JVM). As long as you are running on a machine that conforms to the JVM specification, JRuby can theoretically run your code.
00:01:50.520 There are multiple Java Virtual Machine implementations—believe it or not—such as JRockit by Oracle, J9 by IBM, and Harmony by Apache. I don't know the various details of these implementations at this point, but one thing we can say is that JRuby improves with the JVM's advancements over time.
00:02:04.800 Another reason JRuby can be fast is that it uses faster and more mature garbage collectors. I use the term 'collectors' because the OpenJDK, which is the reference implementation of the JVM specification, has more than one garbage collector, including generational ones and the newer G1 collector. If one doesn't work for you, you can try other garbage collectors.
00:02:20.960 Here’s a graph showing how JVM’s garbage collector performance is superior to Ruby’s. You can see that as memory consumption grows, Ruby's garbage collector takes more time per collection.
00:02:36.640 Now, here's a benchmark of a Compute Mandelbrot set executed on JRuby plotted against MRI. MRI performs fairly well here because JRuby is primarily doing the interpretation of the Ruby program.
00:02:51.760 There is nothing that JRuby currently does to optimize the Ruby code passed to the JVM runtime. Performance can improve significantly if you implement some tricks on the JRuby side, like using the just-in-time (JIT) compiler that comes with the JVM.
00:03:04.480 Regarding web servers, many of you may be Rails programmers. Moving to JRuby may require some changes in your web server because we have a different set of options available, notably TorqueBox, backed by JBoss, which includes an application server with various services you might need, such as messaging and job scheduling.
00:03:23.360 Another option is Puma, written by Evan Phoenix, and finally Trinidad, which is based on Tomcat. TorqueBox, developed by Red Hat, combines messaging, scheduling, caching, and daemon services all in one, so you won't have to set up additional services like delayed jobs or cron tasks.
00:03:40.640 Puma is also compatible with Rubinius and MRI. If you are looking at switching to JRuby, you might want to investigate Puma first. Trinidad is a lightweight option similar to earlier web servers. We will discuss the performance of these options shortly.
00:03:54.960 On the deployment side, you can use platforms like Heroku or OpenShift, or simply host it yourself with EC2.
00:04:10.960 There are also benchmarks available from TechEmpower, with the latest round released in December last year, pitting MRI 2.0 and Unicorn against JRuby 1.7.8 with TorqueBox 3.
00:04:23.840 In the first benchmark regarding JSON serialization, the peak responses per second depend on the web framework you use. The numbers vary widely; however, JRuby generally outperforms Ruby 2.0, except for Sinatra.
00:04:35.920 The next benchmark examines single database queries, where JRuby shows superior performance over Ruby 2.0. We don’t currently have data for version 2.1 as the last round did not include it.
00:04:50.760 For multiple database calls, JRuby significantly outperforms Ruby 2.0. It’s important to note that the performance gains can be attributed to both JRuby and TorqueBox.
00:05:06.960 Let’s look briefly at the history of JRuby. It is surprisingly young, having started in 2001 by a German programmer named Jan Arin Peterson. I haven't met him, but I would like to give him a hug.
00:05:21.440 The project gained traction in 2006, when Rails support was introduced, thanks to the involvement of Charles Nutter and Tom Eneal, the current co-leads of the project.
00:05:37.040 In 2011, we had version 1.6.0, which included experimental C extension support. In 2012, we released 1.7.0 with invoke dynamic support.
00:05:50.160 Last year we released 1.6.8, which may be the last release in the 1.x series. If you are still using 1.6, please consider upgrading to 1.7, which is significantly better.
00:06:05.440 We also released versions 1.7.2 through 1.7.9 last year, and version 1.7.4 introduced experimental Ruby 2.0 support.
00:06:18.960 We branched 1.7 development to move towards the next and best JRuby version ever. We had 2,459 commits in the master branch and 1,939 commits on the 1.7 branch with the split occurring on October 1st.
00:06:35.040 There are many ways JRuby can still improve, and to understand how this can occur, we need to understand JRuby's underlying architecture.
00:06:49.840 At the base, we have the JVM, above which are the JDK and Java libraries. On top of that lie JRuby's core classes and compilers, followed by Ruby itself. Your application will sit on this stack.
00:07:04.080 The JVM is constantly evolving, and JRuby can become faster as the JVM improves. We can see performance benchmarks indicating that as Java updates occur, JRuby benefits without requiring additional work from the JRuby team.
00:07:18.960 With each new version of Java, improvements in performance metrics are notable, while MRI’s performance remains static. The introduction of invoke dynamic in Java 7 is particularly important for JRuby, as it enables quicker dynamic language calls.
00:07:36.960 The initial releases of invoke dynamic did have some stability issues, but these have been mostly ironed out in later updates. The latest version of Java 7 should be stable, especially with Java 8 coming out soon.
00:07:51.440 However, the performance gains from invoke dynamic have not been as significant as initially hoped. We can see performance comparisons between Java 7 and Java 8, which indicate slight improvements.
00:08:07.680 To make JRuby better, there are components like the Foreign Function Interface (FFI) that hold promise. FFI is a Ruby gem available for both MRI and JRuby, and it allows you to call native functions from Ruby code.
00:08:21.920 FFI comes bundled with JRuby and might find further optimizations in Java 9, which is scheduled for release next year.
00:08:35.360 Now, please raise your hands again if you're using JRuby. Great! I think you’ll agree that startup times are a significant pain point for you.
00:08:51.840 Many initialization tasks that JRuby has to perform during startup cannot easily be fixed by anyone, including me or Charlie, due to the need for the JVM to warm up.
00:09:06.960 I want to compare the startup times between MRI 2.0 and JRuby. For example, when executing simple commands like 'rails help', you can see that while MRI might take under a second, JRuby's startup can take considerably longer.
00:09:21.840 However, there are tuning possibilities available to improve JRuby’s performance on the JVM.
00:09:37.280 One utility you can use is called Nailgun, which is bundled with the JRuby distribution. With small changes to your workflow, Nailgun allows you to maintain a warm JVM instance.
00:09:52.720 As a server-client protocol, Nailgun keeps a single JVM running in the background, so when you call your JRuby process next time, it communicates with the already running server instance.
00:10:08.400 While this approach has its drawbacks, such as potential erroneous results due to leftover state, it significantly speeds up subsequent executions.
00:10:22.960 Another way to improve startup performance is with Drip, which initializes a new JVM for each command execution while keeping one ready to go for the next call. Although it uses more memory, it can lead to substantial time savings.
00:10:38.480 Let’s examine how this affects startup time. Running multiple invocations of a basic Rails app, we see that using optimizations, especially with Drip, yields the best performance results.
00:10:52.960 Optimization strategies include adjusting the compilation strategy, allowing you to skip Java class file verification. This can significantly reduce startup time, especially when running tests.
00:11:11.680 Moreover, you can execute extra code on pre-warmed JVM instances to improve performance. JRuby provides built-in commands for optimizing this process.
00:11:29.120 By leveraging pre-boot techniques, you can dramatically improve JRuby's speed when executing Ruby code, making it competitive with C Ruby’s startup times.
00:11:42.480 Looking ahead to 2014, we intend to release JRuby 9000. You might ask why 9000? It’s a nod to several cultural references, particularly an iconic one in anime, suggesting that we're not just incrementing numbers but aiming to make significant improvements.
00:12:00.960 There are many updates happening in JRuby's architecture. The interpreters and compilers will undergo improvements, including the introduction of a new intermediate representation (IR), which will help optimize execution for JRuby.
00:12:15.520 The IR will enhance efficiency by replacing inefficient patterns with optimized code. Utilizing semantic analysis and offering better control flow will greatly improve performance.
00:12:31.280 Truffle is another promising compiler that’s being developed, though it's currently experimental. The combination of IR and Truffle could lead to significant performance enhancements in JRuby.
00:12:45.440 The Ruby layer in JRuby 9000 will be compatible with Ruby 2.1. There's no plan to support Ruby 2.0 going forward, as work has focused on bringing JRuby to a higher standard.
00:13:01.680 Currently, the support for 1.7 is limited to maintenance, and we do welcome contributions from anyone interested in helping improve JRuby.
00:13:16.080 Our support for C extensions has been phased out due to performance limitations and the challenges presented by the global interpreter lock. It was a brave effort, but ultimately, it impeded progress.
00:13:29.520 For the third consecutive year, the JRuby team has applied to be a mentoring organization for Google Summer of Code. If you or someone you know is interested in participating either as a mentor or a student, please get in touch with us.
00:13:41.360 Lastly, I have JRuby stickers with me. If you’d like one, just grab me afterwards. Thank you!
Explore all talks recorded at RubyConf AU 2014
+16