The obscure world of Jruby — JRuby with Rails Under a Microscope
This is a guide for understanding and using Jruby with Ruby on Rails.
It become much easier to understand jruby errors once you understand how options, garbage collectors and JVM works. I spent a lot of time working with jruby recently and I decided to come up with a post that summarize any information I may have found online to better understand what I was dealing with. Most of the information below are a combination of blog posts and articles that helped me better understand how Jruby works under the hood.
What you’ll find in this post:
- What is Ruby?
- Why Should I Use JRuby?
- How to install JRuby?
- What’s JRuby -S
- Where to put the JVM Options?
- What’s the difference between JAVA_OPTS and JRUBY_OPTS?
- JVM options cheat-sheet
- Understanding java.lang.OutOfMemoryError: GC overhead limit exceeded — How Garbage Collection works?
- Solution for OutOfMemoryError in Java & Jruby
- How to solve java.lang.OutOfMemoryError: Java heap space
- How to solve java.lang.OutOfMemoryError: PermGen space
- The main points you should know about Garbage Collection in Java
What is JRuby?
It has set the standard for what it means to do concurrent programming in Ruby. It was the first Ruby implementation to offer thread-level parallelism.
Why Should I Use JRuby?
- Leverage both Java and Ruby libraries (gems)
- Use existing Java platform to deploy Ruby or Ruby on Rails applications.
- The ability to call or extend Java classes from Ruby (including Spring-managed Java beans)
- Leverage the non-verbose and more pleasant experience of writing code with Ruby.
- Leverage multithreading and concurrency
How to install JRuby?
Read the jruby getting started guide.
On OSX when using RVM I do:
$ rvm install jruby
What’s `Jruby -S`?
The recommended way to run rake, gem, rails and other command commands (known as system-level executable commands) in JRuby is to always use jruby -S
$ jruby -S rake db:migrate
The -S parameter tells JRuby to use its version of the installed binary, as opposed to some other version (such as an MRI version) that might be on your PATH.
Where to put the JVM Options?
You can either put them in the JRUBY_OPTS from your command line
you can also load them when starting your server
$ jruby -J-Xmx2G -J-XX:+HeapDumpOnOutOfMemoryError -S rails s puma
If you’re using RVM, you can put export JRUBY_OPTS=”…” in your project’s .rvmrc, at the bottom of the file.
What’s the difference between JAVA_OPTS and JRUBY_OPTS
JAVA_OPTS is used by the `jruby` launcher to pass options to the JVM as it starts. That environment variable does nothing if you use the jruby jar directly.
JRUBY_OPTS is used by both the `jruby` launcher and JRuby itself. When using the launcher, all command-line arguments will work as if passed to the `jruby` command. When using the jar directly, only options processed after the JVM starts will be honored (Ruby compat version, etc). In this latter case, options handled only by the launcher will not work (-Xjit.threshold=# style options, — manage, others you see processed by bin/jruby.bash).
The -J options are processed by the JRuby launcher and used to pass options directly to the JVM. When using the jar directly, remove the -J and pass those options to the `java` command.
There’s no real preference as to which you use. they are all provided as convenience mechanisms for the various launch scenarios.
JVM options cheat-sheet
The command java -help lists the standard options.
How To Specify JVM option
On the basis of how we specify JVM option it can be divided into two parts, JVM Options which starts with –X and those which starts with -XX:
1) JVM Options that begin with -X are non-standard (thy are not guaranteed to be supported on all JVM implementations), and are subject to change without notice in subsequent releases of the JDK.
2) JVM Options or parameters which are specified with -XX are not stable and are not recommended for casual use. These options are subject to change without notice also.
Additional information you should know about JVM options.
1) Boolean JVM options can be turned on with -XX:+ and can be turned off with -XX:-.
2) Numeric JVM Options can be set with -XX:=. Numbers can include ‘m’ or ‘M’ for megabytes, ‘k’ or ‘K’ for kilobytes, and ‘g’ or ‘G’ for gigabytes (for example, 32k is the sa
me as 32768).
3) String JVM options can be set by using -XX:=, and usually used to specify a file, a path, or a list of commands.
HotSpot JVM may use one of 6 combinations of garbage collection algorithms listed below
GC logging options
JVM sizing options
VIEW THE FULL CHEATSHEET ( HotSpot JVM GC options cheat-sheet )
Understanding java.lang.OutOfMemoryError: GC overhead limit exceeded — How Garbage Collection works?
Garbage collection works by employing several GC algorithm e.g. Mark and Sweep. There are different kinds of garbage collector available in Java to collect different area of heap memory e.g. you have serial, parallel and concurrent garbage collector in Java. A new collector called G1 (Garbage first) are also introduced in JDK 1.7. First step to learn about GC is to understand when an object becomes eligible to garbage collection? Since JVM provides memory management, Java developers only care about creating object, they don’t care about cleaning up, that is done by garbage collector, but it can only collect objects which has no live strong reference or it’s not reachable from any thread. If an object, which is suppose to be collected but still live in memory due to unintentional strong reference then it’s known as memory leak in Java. ThreadLocal variables in Java web application can easily cause memory leak.
Important points about Garbage Collection in Java
1) Objects are created on heap in Java irrespective of there scope e.g. local or member variable. while its worth noting that class variables or static members are created in method area of Java memory space and both heap and method area is shared between different thread.
2) Garbage collection is a mechanism provided by Java Virtual Machine to reclaim heap space from objects which are eligible for Garbage collection.
3) Garbage collection relieves Java programmer from memory management which is essential part of C++ programming and gives more time to focus on business logic.
4) Garbage Collection in Java is carried by a daemon thread called Garbage Collector.
5) Before removing an object from memory garbage collection thread invokes finalize() method of that object and gives an opportunity to perform any sort of cleanup required.
6) You cannot force garbage collection in Java; it will only trigger if JVM thinks it needs a garbage collection based on Java heap size.
7) In Java, there are methods like System.gc() and Runtime.gc() which is used to send request of Garbage collection to JVM but it’s not guaranteed that garbage collection will happen.
8) If there is no memory space for creating new object in Heap Java Virtual Machine throws OutOfMemoryError or java.lang.OutOfMemoryError heap space
9) J2SE 5(Java 2 Standard Edition) adds a new feature called Ergonomics goal of ergonomics is to provide good performance from the JVM with minimum of command line tuning.
I’m not going to add When an Object becomes Eligible for Garbage Collection because I don’t think that it’ll help resolve any jruby issue but just in cacse of, you can read the full explanation on Javin Paul’s blog
Solution for GC overhead limit exceeded
There are a few different scenarios which can trigger this error:
- GC elapsed time too high
- Too many Full GC iterations
- Too much time spent in GC
Usually, this error is thrown when there is insufficient space to allocate an object in the Java heap. In this case, The garbage collector cannot make space available to accommodate a new object, and the heap cannot be expanded further. Also, this error may be thrown when there is insufficient native memory to support the loading of a Java class. Solving this error is directly related to solving the OutOfMemoryError.
Some languages define classes at runtime. Every time you run a script, one (or more) new classes are created and they stay in memory forever. If you’re running a server, that means you have a memory leak. By enabling the option -XX:+CMSClassUnloadingEnabled GC will remove classes which are no longer used.
Solution for OutOfMemoryError in Java & Jruby
OutOfMemoryError in Java is one problem which is more due to system’s limitation (memory) rather than due to programming mistakes in most cases though in certain cases you could have a memory leak which causing OutOfMemoryError.
What is java.lang.OutOfMemoryError in Java
OutOfMemoryError in Java is a subclass of java.lang.VirtualMachineError and JVM throws java.lang.OutOfMemoryError when it ran out of memory in the heap. OutOfMemoryError in Java can come anytime in heap mostly while you try to create an object and there is not enough space on the heap to allocate that object.
The difference between “java.lang.OutOfMemoryError: Java heap space” and “java.lang.OutOfMemoryError: PermGen space”
java.lang.OutOfMemoryError: Java heap space
If you are familiar with different generations on the heap and How garbage collection works in java and aware of new, old and permanent generation of heap space then you would have easily figured out this OutOfMemoryError in Java.
java.lang.OutOfMemoryError: PermGen space
Permanent generation of the heap is used to store String pool and various Metadata required by JVM related to Class, method and other java primitives.
Since in most of JVM default size of Perm Space is around “64MB” you can easily run out of memory if you have too many classes or a huge number of Strings in your project.
An important point to remember
It doesn’t depend on –Xmx value so no matter how big your total heap size you can run OutOfMemory in perm space. The good thing is you can specify the size of permanent generation using JVM options “-XX: PermSize” and “-XX: MaxPermSize” based on your project need.
Another reason of “java.lang.OutOfMemoryError: PermGen” is memory leak through Classloaders and it’s very often surfaced in WebServer and application server like tomcat, WebSphere, glassfish or WebLogic.
In Application server different classloaders are used to load different web applications so that you can deploy and undeploy one application without affecting other application on the same server, but while undeploying if container somehow keeps reference of any class loaded by application class loader then that class and all other related class will not be garbage collected and can quickly fill the PermGen space if you deploy and undeploy your application many times.
The solution of “java.lang.OutOfMemoryError: PermGen” are really tricky because first you need to know which class is causing a memory leak and then you need to fix that. Another reason of OutOfMemoryError in PermGen space is if any thread started by the application doesn’t exit when you undeploy your application.
These are just some example of infamous classloader leaks, anybody who is writing code for loading and unloading classes has to be very careful to avoid this.
Another rather unknown but interesting cause of “java.lang.OutOfMemoryError: PermGen” is the introduction of JVM options“-Xnoclassgc”.
This option sometimes used to avoid loading and unloading of classes when there are no further live references of it just to avoid performance hit due to frequent loading and unloading, but using this option is J2EE environment can be very dangerous because many framework e.g. Struts, spring etc uses reflection to create classes and with frequent deployment and undeployment you can easily run out of space in PermGen if earlier references were not cleaned up. This instance also points out that sometimes bad JVM arguments or configuration can cause OutOfMemoryError in Java.
So the conclusion is to avoid using “-Xnoclassgc” in the J2EE environment especially with AppServer.
How to solve java.lang.OutOfMemoryError: Java heap space
1) An easy way to solve OutOfMemoryError in java is to increase the maximum heap size by using JVM options “-Xmx512M”, this will immediately solve your OutOfMemoryError. This is my preferred solution when I get OutOfMemoryError in Eclipse, Maven or ANT while building project because based upon size of project you can easily run out of Memory.here is an example of increasing maximum heap size of JVM, Also its better to keep-Xmx to -Xms ration either 1:1 or 1:1.5 if you are setting heap size in your java application
export JVM_ARGS="-Xms1024m -Xmx1024m"
2) The second way to resolve OutOfMemoryError in Java is rather hard and comes when you don’t have much memory and even after increase maximum heap size you are still getting java.lang.OutOfMemoryError, in this case, you probably want to profile your application and look for any memory leak.
You can use Eclipse Memory Analyzer to examine your heap dump or you can use any profiler like Netbeans or JProbe. This is tough solution and requires some time to analyze and find memory leaks.
How to solve java.lang.OutOfMemoryError: PermGen space
Important Note: Compatibility Guide for JDK 8 says that in Java 8 the command line flag MaxPermSize has been removed. The reason is that the permanent generation was removed from the hotspot heap and was moved to native memory. The permanent generation has been removed. The PermSize and MaxPermSize are ignored and a warning is issued if they are present on the command line.
For older version of JVM < 8
As explained in above paragraph this OutOfMemory error in java comes when Permanent generation of heap filled up. To fix this OutOfMemoryError in Java, you need to increase heap size of Perm space by using JVM option “-XX: MaxPermSize”. You can also specify initial size of Perm space by using“-XX: PermSize” and keeping both initial and maximum Perm Space you can prevent some full garbage collection which may occur when Perm Space gets re-sized. Here is how you can specify initial and maximum Perm size in Java:
export JVM_ARGS="-XX:PermSize=64M -XX:MaxPermSize=256m"
Important Note: From Tomcat > 6.0 onward tomcat provides memory leak detection feature which can detect many common memory leaks on Java application e.g ThreadLocal memory leaks, JDBC driver registration, RMI targes, LogFactory, and Thread spawned by web apps. You can check complete details on htp://wiki.apache.org/tomcat/MemoryLeakProtection. You can also detect memory leak by accessing manager application which comes with tomcat, in case you are experiencing memory leak on any java web app it’s a good idea to run it on tomcat to find out the reason of OutOfMemoryError in PermGen space.
The main points you should know about Garbage Collection in Java
1) Java Heap is divided into three generation for sake of garbage collection. These are young generation, tenured or old generation and Perm area.
2) New objects are created into young generation and subsequently moved to old generation.
3) String pool is created in PermGen area of Heap, garbage collection can occur in perm space but depends upon JVM to JVM. By the way from JDK 1.7 update, String pool is moved to heap area where objects are created.
4) Minor garbage collection is used to move object from eden space to survivor 1 and survivor 2 space and major collection is used to move object from young to tenured generation.
5) Whenever Major garbage collection occurs application threads stops during that period which will reduce application’s performance and throughput.
6) JVM command line options –Xmx and -Xms is used to setup starting and max size for Java Heap. Ideal ratio of this parameter is either 1:1 or 1:1.5 based upon my experience for example you can have either both –Xmx and –Xms as 1GB or –Xms 1.2 GB and 1.8 GB.
7) There is no manual way of doing garbage collection in Java
8) You can choose what types of Garbage collection you want to use based upon your application’s performance requirement.
Here a snippet from Oracle website on how to select a Collector:
Unless your application has rather strict pause time requirements, first run your application and allow the VM to select a collector. If necessary, adjust the heap size to improve performance. If the performance still does not meet your goals, then use the following guidelines as a starting point for selecting a collector.
If the application has a small data set (up to approximately 100MB), then
- select the serial collector with -XX:+UseSerialGC.
If the application will be run on a single processor and there are no pause time requirements, then
- let the VM select the collector, or
- select the serial collector with -XX:+UseSerialGC.
If (a) peak application performance is the first priority and (b) there are no pause time requirements or pauses of one second or longer are acceptable, then
- let the VM select the collector, or
- select the parallel collector with -XX:+UseParallelGC and (optionally) enable parallel compaction with -XX:+UseParallelOldGC
If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then
- select the concurrent collector with -XX:+UseConcMarkSweepGC. If only one or two processors are available, consider using incremental mode, described below.
You can read more about tuning on Oracle article Virtual Machine Garbage Collection Tuning. And read the full session about Selecting a Collector.
These tools will help you profile your application and look for memory leak
Visualgc stands for Visual Garbage Collection Monitoring Tool and you can attach it to your instrumented hotspot JVM. The main strength of visualgc is that it displays all key data graphically including class loader, garbage collection, and JVM compiler performance data.
The target JVM is identified by its virtual machine identifier also called as vmid. You can read more about visualgc and vmid options here.
Use visualgc for monitoring PermGen space, this tool will show the graph of PermGen space and you can see how and when Permanent space getting increased.
Eclipse Memory Analyzer ( FREE )
Eclipse memory analyzer (MAT) is a tool from eclipse foundation to analyze java heap dump. It helps to find classloader leaks and memory leaks and helps to minimize memory consumption.you can use MAT to analyze heap dump carrying millions of object and it also helps you to extract suspect of memory leak. See here for more information.
Good for analyzing heap dump but not free.
Jmap is a command line utility comes with JDK6 and allows you to take a memory dump of the heap in a file. It’s easy to use as shown below:
jmap -dump:format=b,file=heapdump 6054
Here file specifies the name of memory dump file which is “heap dump” and 6054 is PID of your Java progress. You can find the PDI by using “ps -ef” or windows task manager or by using the tool called “jps”(Java Virtual Machine Process Status Tool).
Jhat was earlier known as hat (heap analyzer tool) but it is now part of JDK6. You can use jhat to analyze heap dump file created by using “jmap”. Jhat is also a command line utility and you can run it from cmd window as shown below:
jhat -J-Xmx256m heapdump
Here it will analyze memory dump contained in file “heapdump”. When you start jhat it will read this heap dump file and then start listening on HTTP port, just point your browser into port where jhat is listening by default 7000 and then you can start analyzing objects present in heap dump
Jvisualvm ( FREE )
This is the one i use. It’s good for analyzing heap dump. You can run it from the terminal by typing:
Surprisingly, there aren’t that many books about Jruby on Amazon and the few that exist are actually hold. I hope to see more books in the future.
This Cookbook offers practical solutions for using the Java implementation of the Ruby language, with targeted recipes for deploying Rails web applications on Java servers, integrating JRuby code with Java technologies, developing JRuby desktop applications with Java toolkits, and more
Get it on Amazon
You’ll learn how to call Java objects seamlessly from Ruby, and deal with Java idioms such as interfaces and overloaded functions. Run Ruby code from Java, and make a Java program scriptable in Ruby. See how to compile Ruby into .class files that are callable from Java, Scala, Clojure, or any other JVM language.
Get it on Amazon
This article was entirely put together thanks to amazing sources:
If there are any additional information I can use in this document please contact me on twitter @Richardsondx or comment here.
I also wrote:
- How I Trained to learn rails — A guide for learning ruby on rails in 2 months
- How to get robbed by insecure practices Lesson learned after being hacked and billed $11,146.38 by Amazon Web Services in 17 days in April.
- What I learned about startups from Scuba Diving
- How to approach a Ruby on Rails Developer
- Why Googling is the most important skill a developer *must* have.