The Source for Java Technology Collaboration
User: Password:



Michael Nascimento Santos's Blog

January 2007 Archives


Measuring the size of your objects reloaded

Posted by mister__m on January 12, 2007 at 10:56 AM | Permalink | Comments (2)

The requirements for defining an agent using the java.lang.instrument package have changed since I've done my first experiments with it for calculating the size of arbitrary objects three years ago. Many folks have asked me how to make that sample work with the final API and while I have told them the directions, they have not always succeeded in their task.

So, here are the steps to build a working agent capable of computing the size of your objects. First, let's create the agent class:

package br.com.michaelnascimento.javaagentsample;

import java.lang.instrument.Instrumentation;
import java.util.Calendar;

public class ObjectSizeCalculator {
   private static Instrumentation instrumentation;

   public static void premain(String agentArgs, Instrumentation inst) {
      instrumentation = inst;
   }

   private static long sizeOf(Object o) {
      return instrumentation.getObjectSize(o);
   }

   public static void main(String[] args) {
      System.out.println("Size of Object: " + sizeOf(new Object()));
      System.out.println("Size of direct subclass: " + sizeOf(
            new ObjectSizeCalculator()));
      System.out.println("Size of String \"size\": " + sizeOf("size"));
      System.out.println("Size of Calendar: " + sizeOf(Calendar.getInstance()));   
   }
}

One requirement for an agent that is started with the JVM is to have a premain method with one of two signatures. The other possible one would just take a String.

Now, the main change made to agent definition is that an agent must be packaged on a jar and must be identified by a manifest attribute, Premain-Class. It shouldn't be too hard to do this with your favourite IDE. With NetBeans, you just need to create a Java Application and make the following changes:

  1. Create a MANIFEST.MF file in the root directory of your project with the following content:
    Premain-Class: br.com.michaelnascimento.javaagentsample.ObjectSizeCalculator
    
  2. Configure your project to use this file by adding the following property to nbproject/project.properties:
    manifest.file=MANIFEST.MF
    

Once you build your project, your agent will be properly packaged and ready to be used. To load it, though, you need to use the -javaagent: command-line option to define the jar that contains your agent. If you are using NetBeans, you just need to edit nbproject/project.properties again in order to replace the definition of run.jvmargs by the following one:

run.jvmargs=-javaagent:${dist.jar}

That is it. Running the sample in my machine produces:

Size of Object: 8
Size of direct subclass: 8
Size of String "size": 24
Size of Calendar: 112

As a final note, agents are actually intended to allow your code to redefine classes by replace sections of their bytecode as desired. This technique is used by AspectWerkz and AspectJ, for instance, and can also be used for special tasks, such as enabling/disabling specific monitoring, for instance. The object size calculation capability is there, but it is not its main purpose.

PS: genesis has been the most active project in December. 3.0 RC1 should be out in a few days.



First Java SE 6 bug!

Posted by mister__m on January 11, 2007 at 04:13 PM | Permalink | Comments (1)

As genesis 3.0 is approaching Release Candidate, I decided to test it using the newly released Java SE 6. I ran the test suite and a single test failed, one involving script evaluation (I've blogged about genesis script support almost two years ago). Since JSR-223 was about to become part of Java SE 6, we've added support for it six months ago. By that time, either the test worked or it hadn't been written yet, but the genesis useradmin sample was running flawless. Well, I've filed a bug in genesis issue tracker and after some investigation, narrowed the problem to its real cause. Basically, you cannot invoke a static method that overloads an instance method using variable.method(arg0, arg1). The following test case demonstrates the problem:
package test;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class FunctionsClass {
   public static boolean xpto(Object arg1, Object arg2) {
      return equals(arg1, arg2);
   }
   
   public static boolean equals(Object arg1, Object arg2) {
      return arg1 == null ? arg2 == null : arg1.equals(arg2);
   }
   
   public static Object echo(Object o) {
      return o;
   }

   public static void main(String[] args) throws Exception {
      ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
      engine.put("f", new FunctionsClass());
      System.out.println(engine.eval("f.echo(f)"));
      System.out.println(engine.eval("f.xpto('a', 'a')"));
      System.out.println(engine.eval("f.equals('a', 'a')"));
   }
}
This test output should be something like:
test.FunctionsClass@14a9972
true
true
it actually is:
test.FunctionsClass@14a9972
true
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: Can't find method java.lang.Object.equals(string,string). (#1) in  at line number 1
       at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:110)
       at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:124)
       at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:247)
       at test.FunctionsClass.main(FunctionsClass.java:24)
If you can change the script or the class being called, it is easy to work around this issue (by invoking the method on the class itself with, renaming it or rewriting it to become an instance method). However, if you cannot, you better use Rhino directly. When I run the same test using BSF over Rhino, it works. For future reference, this has been filed as bug # 6512123 (it might take one or two days for it to show up). Let's hope the fix make it to Java SE 6 Update 1. :-)



Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds