Java Bytecode anschauen

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Wer sich schon immer mal anschauen wollte, was euer Java Kompiler (z.Bsp. der von Sun) so aus euren Programmen macht der / (oder die) jenige kann ja mal folgendes Versuchen:

Wir wollen uns den bytecode dieses Java Prorgamms anschauen.
Code:
/*
 * Created on 04.05.2005@17:03:49 by Darimont
 *
 * TODO Licence info
 */
package de.tutorials;

/**
 * @author Darimont TODO Explain me
 */
public class FooTest {

	public static void main(String[] args) {
		long time = -System.currentTimeMillis();
		methodA();
		System.out.println(time + System.currentTimeMillis());

		time = -System.currentTimeMillis();
		methodB();
		System.out.println(time + System.currentTimeMillis());
	}

	/**
	 * 
	 */
	private static void methodB() {
		int i = 0;
		while (i <= 1000000000) {
			int foo = i + 5;
			i++;
		}
	}

	/**
	 * 
	 */
	private static void methodA() {
		int foo = 0;
		int i = 0;
		while (i <= 1000000000) {
			foo = i + 5;
			i++;
		}
	}
}

Dazu lassen wir das ganze Kompilieren und begeben uns über eine Shell auf die Suche nach dem erzeugten Classfile.

Wir verwenden nun das kleine Programm javap mit welchem wir das Classfile Disassemblen können. Mittels der Option -private bestimmen wir, dass auch private Methoden disassembliert werden sollen.

Nun geben wir folgenden Befehl ein
Code:
E:\eclipse\3.1M6\eclipse\workspace\de.tutorials.training\bin>
javap -c -private de.tutorials.FooTest

Compiled from "FooTest.java"
public class de.tutorials.FooTest extends java.lang.Object{
public de.tutorials.FooTest();
  Code:
   0:   aload_0
   1:   invokespecial   #9; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #21; //Method java/lang/System.currentTimeMillis:()J
   3:   lneg
   4:   lstore_1
   5:   invokestatic    #24; //Method methodA:()V
   8:   getstatic       #28; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  lload_1
   12:  invokestatic    #21; //Method java/lang/System.currentTimeMillis:()J
   15:  ladd
   16:  invokevirtual   #34; //Method java/io/PrintStream.println:(J)V
   19:  invokestatic    #21; //Method java/lang/System.currentTimeMillis:()J
   22:  lneg
   23:  lstore_1
   24:  invokestatic    #37; //Method methodB:()V
   27:  getstatic       #28; //Field java/lang/System.out:Ljava/io/PrintStream;
   30:  lload_1
   31:  invokestatic    #21; //Method java/lang/System.currentTimeMillis:()J
   34:  ladd
   35:  invokevirtual   #34; //Method java/io/PrintStream.println:(J)V
   38:  return

private static void methodB();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   goto    12
   5:   iload_0
   6:   iconst_5
   7:   iadd
   8:   istore_1
   9:   iinc    0, 1
   12:  iload_0
   13:  ldc     #42; //int 1000000000
   15:  if_icmple       5
   18:  return

private static void methodA();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iconst_0
   3:   istore_1
   4:   goto    14
   7:   iload_1
   8:   iconst_5
   9:   iadd
   10:  istore_0
   11:  iinc    1, 1
   14:  iload_1
   15:  ldc     #42; //int 1000000000
   17:  if_icmple       7
   20:  return

}
E:\eclipse\3.1M6\eclipse\workspace\de.tutorials.training\bin>

hier hab ich mal versucht die beiden Methoden etwas genauer zu Beschreiben:
Code:
private static void methodB();
  Code:
   0:   iconst_0 // Lege int mit Wert 0 auf den Stack
   1:   istore_0 // Nimmt den int vom Stack und speichert ihn in der lokalen Variablen(0)
   2:   goto    12 //gehe zur Marke 12
   5:   iload_0 // lege lokale Variable(0) auf den Stack
   6:   iconst_5 // Lege int mit Wert 5 auf den Stack
   7:   iadd // Nehme zwei int Werte vom Stack, addiere diese und lege das Ergebnis zurück
   8:   istore_1 // Nimmt den int vom Stack und speichert ihn in der lokalen Variablen(1)
   9:   iinc    0, 1 // Inkrementiere die lokale variable(0) um 1
   12:  iload_0 // lege lokale Variable(0) auf den Stack
   13:  ldc     #42; //int 1000000000  // lege int mit Wert 1000000000   auf den Stack
   15:  if_icmple       5 // Nimmt die beiden obersten Werte vom Stack und vergleicht diese. Wenn der Wert(0)<=Wert(1) dann springe zur Marke 5
   18:  return // return. Blockabschluss

------------------------------------------------------

private static void methodA();
  Code:
   0:   iconst_0 // Lege int mit Wert 0 auf den Stack

   1:   istore_0 // Nimmt den int vom Stack und speichert ihn in der lokalen Variablen(0)
   2:   iconst_0 // Lege int mit Wert 0 auf den Stack
   3:   istore_1 // Nimmt den int vom Stack und speichert ihn in der lokalen Variablen(1)
   4:   goto    14 //Gehe zur Marke 14
   7:   iload_1 // lege lokale Variable(1) auf den Stack
   8:   iconst_5 // Lege int mit Wert 5 auf den Stack
   9:   iadd // Nehme zwei int Werte vom Stack, addiere diese und lege das Ergebnis zurück auf den Stack.
   10:  istore_0 // Nimmt den int vom Stack und speichert ihn in der lokalen Variablen(0)
   11:  iinc    1, 1 // Inkrementiere die Lokale Variable(1) um 1
   14:  iload_1 // lege lokale Variable(1) auf den Stack
   15:  ldc     #42; //int 1000000000 // lege int mit (int) Wert 1000000000   auf den Stack
   17:  if_icmple       7 //Nimmt die beiden obersten Werte vom Stack und vergleicht diese. Wenn der Wert(0)<=Wert(1) dann springe zur Marke 7
   20:  return // return. Blockabschluss

Erklärungen zu den einzelnen OpCodes findet man z.Bsp. hier:
http://www.tutorials.de/tutorials203705.html

Gruß Tom
 

Neue Beiträge

Zurück