1. 程式人生 > >3.深入jvm核心-原理、診斷與優化-10. jvm位元組碼執行

3.深入jvm核心-原理、診斷與優化-10. jvm位元組碼執行

一、位元組碼

javap
簡單的位元組碼執行過程
常用的位元組碼
使用ASM生成Java位元組碼
JIT及其相關引數
  1. javap(class檔案反彙編工具)

    	public class Calc {
    		public int calc() {
    			int a = 500;
    			int b = 200;
    			int c = 50;
    			return (a + b) / c;
    		}
    	}
    
     javap –verbose Calc
    

  2. 簡單的位元組碼執行過程

  3. 常用的位元組碼

  4. 常用的位元組碼

  5. 使用ASM生成Java位元組碼

    例子:

        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>5.0.3</version>
        </dependency>
    

    GrandParent.java

    	public class GrandParent {
    		public void test() {
    				System.out.println("test of GrandParent");
    		}
    	}
    

    Parent.java

    	public class Parent extends GrandParent{
    		public void test() {
    			System.out.println("test of Parent");
    		}
    	}
    

    Son.java

    	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): [email protected]
    	 * [@email](https://my.oschina.net/u/159820): [email protected]
    	 * @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: [email protected]
    	 * @email: [email protected]
    	 * @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: [email protected]
    	 * @email: [email protected]
    	 * @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: [email protected]
    	 * @email: [email protected]
    	 * @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....");
    		}
    	}
    
  6. JIT及其相關引數

     位元組碼執行效能較差,所以可以對於熱點程式碼編譯成機器碼再執行,在執行時的編譯,
     叫做JIT Just-In-Time
     JIT的基本思路是,將熱點程式碼,就是執行比較頻繁的程式碼,編譯成機器碼。