Among my friends, it’s not a secret that I personally don’t like Java. During my time at the university, I had to deal with it for some courses, but somehow nobody could convince me to really like the language. With Ruby, it was the exact opposite – I saw a few code examples, read some articles about it and I immediately started to like the language and its charming way of doing OO like I always wanted it to be.
When I discovered JRuby, I therefore didn’t take it serious and overlooked its potential. Today, I’m starting to like JRuby. Why? Because JRuby is actually pretty cool. It runs code of my favorite language (Ruby) on a wide-spread and highly optimized platform (the Java Virtual Machine, aka JVM). You can use JRuby to run Ruby code without even knowing a single bit about Java – but it runs on the JVM (which has several advantages as stated below).
Java actually consists of two different parts. On the one hand, there’s the Java compiler that reads programs written in the Java language and translates them to bytecode – and on the other hand, there’s the Java Virtual Machine that executes bytecode. But the JVM doesn’t only run Java programs – actually there are several compilers that translate various programming languages into bytecode that runs on a JVM – amongst them is JRuby which compiles my favorite programming language into bytecode for a JVM.
Interestingly, JRuby seems to have hard times getting accepted in the Ruby community. Charles Nutter from the JRuby team recently told how he experienced hate and anger against JRuby in the Ruby community – in contrary to the Python community, where Jython is very appreciated. That’s kind of strange, since even Matz seems to like JRuby. I have to admit that I also found JRuby uninteresting at first. I didn’t hate it, I just (to quote Charles) ”… found it interesting … for Java developers”. Today, I’m starting to like JRuby, and here’s why:
JVM runtime optimization
The Java VM is a runtime environment that has been worked on for years now and can be considered very stable and mature. It does pretty cool stuff to optimize the runtime execution of bytecode. There are two execution modes: In
-client mode (which is the default), the program startup time and memory usage is minimized (which is good for a local application or an applet, since you usually want to bring it up fast if you start it). The other mode
-server optimizes for runtime speed; an application takes more time to start up and needs more memory in this mode, but it runs slightly faster. The JVM can even dynamically optimize the bytecode during runtime (e.g. optimize inner loops). Therefore, a server application becomes faster after a while, once the JVM has “warmed up”. Compared to the original Ruby (also called MRI), JRuby runs faster, but needs more memory.
The memory usage of a single instance of a Ruby application is higher in JRuby if compared to original Ruby. However, this drawback disappears if you run multiple application instances (like multiple mongrels on a production server). JRuby can run multiple instances of an application in a single JVM (e.g. with jrubysrv). This way, memory can be shared between application instances so that e.g. the Rails framework is only kept in memory once. I don’t have any practical experience with this topic, but JRuby is told to be more memory efficient especially when running many smaller applications on a single server.
JRuby has real native threads so you can easily spread work on multiple processor cores. And with upcoming thread-safe Rails 2.2, it’ll greatly reduce the memory usage of a Rails application.
The JVM is told to have a great garbage collection, making memory usage more efficient. (However, I don’t have any experience on this topic yet).
JIT and AOT compilation
We all love open source software, but to be honest, sometimes there are situations in business where you cannot or don’t want to give out the source (no, I don’t want to hide my bad coding style… it’s just that most companies aren’t happy with publishing sources). Using ahead-of-time (AOT) compilation, an application can be compiled into bytecode and can therefore be shared without exposing the source.
Integration with Java libraries
From JRuby, you can use other Java libraries and vice-versa. This one is mostly unimportant to me, since I don’t use/know Java libraries, but this feature probably is very attractive to Java programmers who want to switch to Ruby.
Running Rails applications on existing Java application servers
Using Warbler, a Rails application can easily be packed into a .WAR file, which is the default archive format for a Java web application. Warbler packs the Rails application, all required gems, the JRuby library and a little wrapper plus the required metadata into a .WAR file. This way, the resulting .WAR file can be easily deployed to an existing application server infrastructure. This compatibility certainly is attractive for people with existing java application servers.
Documentation and Specs
JRuby (amongst others) is told to bring the Ruby language a big step forward by helping to create a clear language documentation and language specs. The language itself was told to be not so well documented and MRI’s release management is told to be kind of clumsy. (more on this in the Google talk about Rails scalability; again, I don’t have personal experiences here).
Nothing comes without a price – so here are the JRuby disadvantages I found so far.
Larger memory footprint and startup time
A single JRuby instance needs more memory than a single Ruby instance, but in a typical production server environment with multiple mongrels, memory can be shared so that I expect a lower or at least equal memory usage in total. JRuby’s startup time is higher than MRI, but once the JVM has “warmed up” after a few minutes, it usually runs faster than MRI.
No native C extension
Due to the nature of Java, it is impossible to run any native extension. So there are several gems that don’t work since they rely on a C extension. However, there’s ongoing effort to create alternative gems that are compatible to JRuby. E.g. mongrel uses a native C extension, but if you install the mongrel gem using JRuby, it automatically installs a java-enhanced version.
JRuby is not technically complete
It’s told that there are cases where JRuby is not 100% compatible with MRI, however, I think these are very special cases; at least I didn’t encounter any problems yet. Big Frameworks like Rails are tested with JRuby, so I currently don’t expect any problems with it.
I’m starting to like JRuby and I think I’ll use it in production for my next project to see myself how it works out. However, for development, I currently still use MRI since the long startup time of JRuby is kind of annoying during development.