Ruby Objects on the JRuby Heap at Runtime

I wrote an entry last week about using jhat to get a static snapshot of the Ruby objects on the JRuby heap. The next step is to try getting similar information from a running application, with periodic updates. In other words, look inside the JRuby code as it runs on the JVM and find out the number of Ruby objects that have been allocated, broken down by the Ruby class for each object.

The tool I chose this time was BTrace. The "B" stands for "Bytecode" and BTrace provides a "roll your own" profiling capability. In other words, you get complete control over exactly what gets instrumented in your Java application. The trade-off, in comparison to other profiling tools, is you have to do more of the work. Specifically, you have to write scripts that control the instrumentation. Luckily the scripting language is familiar: Java, along with some annotations that BTrace provides.

BTrace is a simple command line utility that just needs the process ID of the JVM to instrument and the name of a script file (you can provide the .java source file or use btracec to create a .class file). In order to experiment with it, I needed a Ruby program that would create lots of objects. I wrote this simple application:

class Every
end

class EveryOther
end

puts "Hello World"
i = 0;
all = Array.new
some = Array.new
while (true) 
  some[i] = EveryOther.new if (i%2==0)
  all[i] = Every.new
  puts i if (i%1000000==0)
  i+=1
end


It just has an endless loop that allocates objects. I am using JRuby 1.1 to run it and I pass -J-Xmx2048m on the JRuby command line so that the program can run for quite a while before using up all the heap space and exiting with an OutOfMemoryError.

My BTrace script is:

package org.jruby;

import com.sun.btrace.annotations.\*;
import static com.sun.btrace.BTraceUtils.\*;
import com.sun.btrace.aggregation.Aggregation;
import com.sun.btrace.aggregation.AggregationFunction;
import com.sun.btrace.aggregation.AggregationKey;

/\*\*
 \* Create a histogram of RubyObject instances, 
 \* keyed by RubyClass classId.
 \* @author Gregg Sporar
\*/
@BTrace
public class RubyClassHistogram {
   private static Aggregation sum = newAggregation(AggregationFunction.SUM);

   /\*
    \* Instrument the public RubyObject contstructor 
    \*/
    @OnMethod(
        clazz="org.jruby.RubyObject",
        method="<init>",
        type="void (org.jruby.Ruby, org.jruby.RubyClass)"
    ) 
    public static void onNewObject(org.jruby.RubyObject self,
                                   org.jruby.Ruby ruby,
                                   org.jruby.RubyClass rubyClass) {
        String classId = rubyClass.classId;
        AggregationKey key = newAggregationKey(classId);
        addToAggregation(sum, key, 1);
    }

    @OnTimer(4000) 
    public static void print() {
        printAggregation("RubyObject Instances Created:", sum);
    }
}

BTrace calls my print() method every 4 seconds to display the current values in the histogram. As an example:


RubyObject Instances Created:
  String                                                           18
  EveryOther                                                  2934364
  Every                                                       5868731

Please note:

  • The histogram is of the number of objects created, not the number of objects that are currently alive on the heap. With the toy sample application that I used, those numbers are the same, but with real applications the number of live objects is usually smaller than the total number of objects that have been created. I do not have much knowledge of the internals of JRuby, but I am guessing the BTrace script above could be enhanced to also instrument the method in JRuby that removes a Ruby object from the JRuby heap.
  • BTrace requires JDK 6 or higher.
  • BTrace is still under development - use it at your own risk. From what I have seen and heard, it appears to be robust and stable but I do not know if I would use it on a production system. In particular, I do not have enough experience with it yet to have a good feel for the amount of overhead that it would introduce when used with a script like the one shown here.

Comments:

Post a Comment:
Comments are closed for this entry.
About

Gregg Sporar

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today