1、字節碼java
javap 簡單的字節碼執行過程 經常使用的字節碼 使用ASM生成Java字節碼 JIT及其相關參數
javap(class文件反彙編工具)web
public class Calc { public int calc() { int a = 500; int b = 200; int c = 50; return (a + b) / c; } }
javap –verbose Calc
簡單的字節碼執行過程app
經常使用的字節碼jvm
經常使用的字節碼工具
使用ASM生成Java字節碼性能
例子:this
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>5.0.3</version> </dependency>
GrandParent.java.net
public class GrandParent { public void test() { System.out.println("test of GrandParent"); } }
Parent.java3d
public class Parent extends GrandParent{ public void test() { System.out.println("test of Parent"); } }
Son.javacode
public class Son extends Parent{ public void test() { System.out.println("test of Son"); } }
ASMByteCodeManipulation.java
/** * description: * * [@author](https://my.oschina.net/arthor): dawn.he QQ: 905845006 * [@email](https://my.oschina.net/u/159820): dawn.he@cloudwise.com * [@email](https://my.oschina.net/u/159820): 905845006@qq.com * @date: 2019/9/30 9:21 PM */ import java.io.FileOutputStream; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class ASMByteCodeManipulation extends ClassLoader implements Opcodes { public static void main(String args[]) throws Exception { test1(); // test2(); } //print hello word public static void test1() throws Exception{ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); cw.visit(V1_7, ACC_PUBLIC, "Example", null, "java/lang/Object", null); MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); //this 入棧 //使用invokespecial這種方式也有侷限,只能從子類調用。不然報錯: mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(0, 0); mw.visitEnd(); mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mw.visitLdcInsn("Hello world!"); mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mw.visitInsn(RETURN); mw.visitMaxs(0,0); mw.visitEnd(); byte[] code = cw.toByteArray(); ASMByteCodeManipulation loader = new ASMByteCodeManipulation(); Class exampleClass = loader .defineClass("Example", code, 0, code.length); exampleClass.getMethods()[0].invoke(null, new Object[] { null }); } //print hello word public static void test2() throws Exception{ ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC, "Example", null, "Son", null); // creates a MethodWriter for the (implicit) constructor MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Son", "<init>", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); // creates a MethodWriter for the 'test' method mw = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null); mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mw.visitLdcInsn("test of AI3"); mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "GrandParent", "test", "()V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Parent", "test", "()V"); //Call test() of GrandParent mw.visitVarInsn(ALOAD, 0); mw.visitMethodInsn(INVOKESPECIAL, "Son", "test", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(2, 1); mw.visitEnd(); byte[] code = cw.toByteArray(); FileOutputStream fos = new FileOutputStream("Example.class"); fos.write(code); fos.close(); ASMByteCodeManipulation loader = new ASMByteCodeManipulation(); Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length); Object obj = exampleClass.newInstance(); exampleClass.getMethod("test", null).invoke(obj, null); } }
test2方法生成的class文件
public class Example extends Son { public Example() { } public void test() { System.out.println("test of AI3"); super.test(); super.test(); super.test(); } }
例子2:
Account.java
public class Account { public void operation() { System.out.println("operation...."); } }
要嵌入的內容
SecurityChecker.java
public class SecurityChecker { public static boolean checkSecurity() { System.out.println("SecurityChecker.checkSecurity ..."); return true; } }
AddSecurityCheckClassAdapter.java
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:39 PM */ public class AddSecurityCheckClassAdapter extends ClassVisitor { public AddSecurityCheckClassAdapter( ClassVisitor cv) { super(Opcodes.ASM5, cv); } // 重寫 visitMethod,訪問到 "operation" 方法時, // 給出自定義 MethodVisitor,實際改寫方法內容 public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions); MethodVisitor wrappedMv = mv; if (mv != null) { // 對於 "operation" 方法 if (name.equals("operation")) { // 使用自定義 MethodVisitor,實際改寫方法內容 wrappedMv = new AddSecurityCheckMethodAdapter(mv); } } return wrappedMv; } }
AddSecurityCheckMethodAdapter.java
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:40 PM */ public class AddSecurityCheckMethodAdapter extends MethodVisitor { public AddSecurityCheckMethodAdapter(MethodVisitor mv) { super(Opcodes.ASM5,mv); } public void visitCode() { // visitMethodInsn(Opcodes.INVOKESTATIC, "geym/jvm/ch10/asm/SecurityChecker", visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker", "checkSecurity", "()Z"); super.visitCode(); } }
Generator.java
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import java.io.File; import java.io.FileOutputStream; /** * description: * * @author: dawn.he QQ: 905845006 * @email: dawn.he@cloudwise.com * @email: 905845006@qq.com * @date: 2019/9/30 10:40 PM */ public class Generator extends ClassLoader { public static void main(String args[]) throws Exception { // ClassReader cr = new ClassReader("geym.jvm.ch10.asm.Account"); ClassReader cr = new ClassReader("Account"); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); AddSecurityCheckClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw); cr.accept(classAdapter, ClassReader.SKIP_DEBUG); byte[] data = cw.toByteArray(); //class文件寫到哪裏 // File file = new File("bin/geym/jvm/ch10/asm/Account.class"); File file = new File("Account.class"); FileOutputStream fout = new FileOutputStream(file); fout.write(data); fout.close(); Generator loader = new Generator(); Class<?> exampleClass = loader.defineClass("Account", data, 0, data.length); Object obj = exampleClass.newInstance(); exampleClass.getMethod("operation", null).invoke(obj, null); } }
執行完main方法 輸出:
SecurityChecker.checkSecurity ... operation....
生成的class
Account.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // public class Account { public Account() { } public void operation() { SecurityChecker.checkSecurity(); System.out.println("operation...."); } }
JIT及其相關參數
字節碼執行性能較差,因此能夠對於熱點代碼編譯成機器碼再執行,在運行時的編譯, 叫作JIT Just-In-Time JIT的基本思路是,將熱點代碼,就是執行比較頻繁的代碼,編譯成機器碼。