Pages

Sunday, January 16, 2011

Java snippet: get PID at runtime

package my.pid;

import java.lang.management.ManagementFactory;

public class MyPid {
  public static void main(String[] args) {
    String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
    int p = nameOfRunningVM.indexOf('@');
    String pid = nameOfRunningVM.substring(0, p);
    System.out.println("Java app PID: " + pid);
  }
}

Sunday, January 2, 2011

Java Bytecode Fundamentals

Java bytecode is a bread and butter of JRebel, the productivity tool for Java developers. This is why I decided that it would be a good thing to write a blog post on this subject. This blog post is a summary of various sources that I've found while googling on the subject. Hopefully someone may find it relevant and useful. What is a little weird is that there's not much information on the subject, either books or articles. BTW, if you have anything to add or comment - don't hesitate to post to comments :)

UPDATE This blog post, along with many improvements is a part of my article for RebelLabs' report on Java Bytecode that can be found here: http://zeroturnaround.com/rebellabs/rebel-labs-report-mastering-java-bytecode-at-the-core-of-the-jvm/


The developers who use Java for application development, usually do not need to be aware of the bytecode that is being executed in the VM. However, those developers who implement the state-of-the-art frameworks, compilers, or even Java tooling - may need to understand and may even be using bytecode directly. While special libraries (like ASM, cglib, Javassist) do help regarding bytecode manipulation, it is still important to understand the fundamentals in order to make the effective use of those tools.


Let's start off with a simple example - a POJO, with one field, a getter and a setter.

public class Foo {
    private String bar;

    public String getBar(){ 
      return bar; 
    }

    public void setBar(String bar) {
      this.bar = bar;
    }
  }

First of all, one you compile the class using javac Foo.java, you'll have the Foo.class, which now contains the bytecode. Here's how it looks in the hex editor:


Each pair of hex numbers (a byte) is actually translatable to opcodes (mnemonics), but obviously it would be too brutal to start reading it in the binary format. Let's proceed to the mnemonical representation.

Executing javap -c Foo will print out the bytecode:
public class Foo extends java.lang.Object {
public Foo();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public java.lang.String getBar();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field bar:Ljava/lang/String;
   4:   areturn

public void setBar(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #2; //Field bar:Ljava/lang/String;
   5:   return

}
The class is very simple and it is easy to see the relation between the sourced code and the generated bytecode. First of all we notice that in the bytecode version of the class the compiler inferred the default constructor (as promised by the JVM spec).

Disqus for Code Impossible