主頁 >  其他 > JVM學習筆記之class檔案結構【七】

JVM學習筆記之class檔案結構【七】

2021-04-01 18:48:41 其他

一、概念

1.1 無符號數:

以 u1、u2、u3、u4、u8 代表 1 個位元組,2 個位元組、4 個位元組、8 個位元組的無符號數,無符號數可以描述數字,索引參考、數量值和按照 UTF-8 編碼構成的字串值,

1.2 表

  • 表是由多個無符號數或其他表作為資料項構成的復合的資料結構,所有表都習慣性的以“_info”結尾,表用于表示有層次關系的復合結構的資料,整個 Class 檔案本質上是一張表

1.3 class 檔案組成

ClassFile {
    u4             magic;  //魔數, 用于識別class檔案格式
    u2             minor_version;//次版本號
    u2             major_version;//主版本號
    u2             constant_pool_count;  //常量池計數器
    cp_info        constant_pool[constant_pool_count-1]; //常量池
    u2             access_flags;//訪問標志
    u2             this_class;//類索引
    u2             super_class;//父類索引
    u2             interfaces_count;//介面計數器
    u2             interfaces[interfaces_count];//介面索引集合
    u2             fields_count;//欄位計數器
    field_info     fields[fields_count];//欄位表集合
    u2             methods_count;//方法計數器
    method_info    methods[methods_count];//方法表
    u2             attributes_count; //屬性計數器
    attribute_info attributes[attributes_count];附加屬性表
}

1.4 魔數

每個 Class 檔案的頭 4 個位元組被稱為魔數(Magic Number),它的唯一作用是確定這個檔案是否能被虛擬機接受的 Class 檔案,它的值是 0xCAFEBABE (咖啡寶貝),非常容易記憶,

1.5 版本號

緊接著的位元組是次版本號(minor_version)和主版本號(major_version),Java 的版本號從 45 開始,Java1.1 之后的 JDK 大版本發布主版本號向上加一(Java1.0~Java1.1 使用了 45.0~45.3 的版本號),注意高版本的 JDK 能向下兼容 以前的 Class 檔案,但不能運行以后版本的 Class 檔案,

1.6 常量池

常量池可以理解為 Class 檔案的資源倉庫,

主要存放:

  • 字面量(Literal)

  • 符號參考(Symbolic References)

    • 類和介面的全限定名(Full Qualified Name)
    • 欄位的名稱描述符(Descriptor)
    • 方法的名稱和描述符
    型別 標識 描述
    CONSTANT_Class 7 類或介面的符號參考
    CONSTANT_Fieldref 9 欄位的符號參考
    CONSTANT_Methodref 10 方法的符號參考
    CONSTANT_InterfaceMethodref 11 介面中方法的符號參考
    CONSTANT_String 8 字串型別字面量
    CONSTANT_Integer 3 整型字面量
    CONSTANT_Float 4 浮點型字面量
    CONSTANT_Long 5 長整型字面量
    CONSTANT_Double 6 雙精度浮點型字面量
    CONSTANT_NameAndType 12 欄位或方法的部分符號參考
    CONSTANT_Utf8 1 UTF-8 編碼字串
    CONSTANT_MethodHandle 15 標識方法句柄
    CONSTANT_MethodType 16 標識方法型別
    CONSTANT_InvokeDynamic 18 動態方法呼叫點

1.7 訪問標識(access_flags)

用于識別類和介面層次的訪問資訊

Flag Name Value Interpretation
ACC_PUBLIC 0x0001 是否為被宣告為 public ,可以被其他外部包中訪問
ACC_FINAL 0x0010 是否被宣告 final,不能派生子類
ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_INTERFACE 0x0200 標識一個介面
ACC_ABSTRACT 0x0400 宣告 abstract,抽象類,不能實體化
ACC_SYNTHETIC 0x1000 宣告 synthetic; 標識這個類并非有用戶代碼產生
ACC_ANNOTATION 0x2000 標識這個一個注解
ACC_ENUM 0x4000 標識這是一個列舉

1.8 類索引、父類索引和介面索引

Class 檔案就是由這三項資料來確定這個類的繼承關系,類索參考于確定類的全限定類名,父索參考于確定父類的全限定類名,介面索引集合用于描述類實作了那些介面,

1.9 欄位表集合

欄位表集合[field_info] 用于描述介面或者類中宣告的變數,欄位(field) 包括類變數和實體變數,但不包括方法內部宣告的區域變數,

  • 欄位表結構

    field_info {
        u2             access_flags; //訪問標識
        u2             name_index; //名稱索引
        u2             descriptor_index;  //描述符索引
        u2             attributes_count;  //屬性計數器
        attribute_info attributes[attributes_count];  //屬性表
    }
    
  • 欄位包含的資訊:

    • 作用域(public 、private、protected 修飾符)
    • static 修飾符
    • 可變性 final
    • 并發可見性 volatile
    • 可否序列化 transient
    • 欄位型別 【基本資料型別(byte、char、short、int、long 、float、double、boolean)、物件、陣列】
  • 欄位訪問標志

    ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its package.
    ACC_PRIVATE 0x0002 宣告 private;
    ACC_PROTECTED 0x0004 宣告 protected;
    ACC_STATIC 0x0008 宣告 static.
    ACC_FINAL 0x0010 宣告 final;
    ACC_VOLATILE 0x0040 宣告 volatile;
    ACC_TRANSIENT 0x0080 宣告 transient;
    ACC_SYNTHETIC 0x1000 宣告 synthetic; 欄位是否有編譯器自動產生的
    ACC_ENUM 0x4000 宣告欄位是否是列舉
  • 簡單名稱:沒有型別和引數修飾的方法或者欄位名稱,如 inc()和 m 欄位的簡稱為 inc 和 m

  • 全限定名:com/demo/TestClass; “;”標識類的全限定名結束

  • 描述符:用于描述欄位的資料型別,方法的引數串列(數量、型別、順序)和回傳值

    標識字符 代表型別 描述
    B byte 基本型別 byte
    C char 基本型別 char
    D double 基本型別 double
    F float 基本型別 float
    I int 基本型別 int
    J long 基本型別 long
    L ClassName ; reference 物件型別,如 : Ljava/lang/Object
    S short 基本型別 short
    Z boolean j 基本型別 boolean
    [ reference 陣列型別 ,如陣列int[] 被記錄為 [I,陣列String[][]被記錄為 [[java/lang/String
    V void 特殊型別 Void

描述符來描述方法時,按照先引數串列,后回傳值的順序描述;如:java.lang.String.toString() 描述為 () Ljava/lang/String,java.lang.String#valueOf(char[], int, int) 描述為 ([CII)Ljava/lang/String

1.10 方法表集合

方法描述采取與欄位描述完全一致的方式,

  • 方法表結構

    method_info {
        u2             access_flags;
        u2             name_index;
        u2             descriptor_index;
        u2             attributes_count;
        attribute_info attributes[attributes_count];
    }
    
  • 相關訪問標識

    Flag Name Value Interpretation
    ACC_PUBLIC 0x0001 方法是否 public
    ACC_PRIVATE 0x0002 方法是否 private
    ACC_PROTECTED 0x0004 方法是否 protected;
    ACC_STATIC 0x0008 方法是否 static.
    ACC_FINAL 0x0010 方法是否 final;
    ACC_SYNCHRONIZED 0x0020 方法是否 synchronized; 標識同步方法
    ACC_BRIDGE 0x0040 標識是否由編譯器生成的橋接方法
    ACC_VARARGS 0x0080 方法是否接受不定引數
    ACC_NATIVE 0x0100 方法是否 native;
    ACC_ABSTRACT 0x0400 方法是否 abstract;
    ACC_STRICT 0x0800 方法是否 strictfp;
    ACC_SYNTHETIC 0x1000 方法是否為 synthetic;
  • 方法里定義的代碼

    方法里面的代碼,經過編譯器編譯成位元組指令后,存放在方法屬性表集合,名為 Code 屬性里,

1.11 屬性表集合在

屬性表(attribute_info)在 Class 檔案、欄位表、方法表中都可以攜帶自己的屬性表集合,用于描述某些場景專有的資訊,

  • 格式結構

    attribute_info {
        u2 attribute_name_index;
        u4 attribute_length;
        u1 info[attribute_length];
    }
    
  • 虛擬機預定義屬性

    屬性 位置 含義 class 版本
    SourceFile ClassFile 記錄源檔案名稱 45.3
    InnerClasses ClassFile 內部類串列 45.3
    EnclosingMethod ClassFile 僅當一個類為區域類或匿名類時才能擁有這個屬性,這個屬性用于標識這個類所在的外圍方法 49.0
    SourceDebugExtension ClassFile JDK 1.6 中新增的屬性,SourccDcbugExtcnsion 屬性用于在儲額外的除錯資訊,譬如在進行 JSP 檔案除錯時,無法通過 Java 堆疊來定位到 JSP 檔案的行號, JSR-45 規范為這些非 Java 語言撰寫,卻需要編譯成位元組碼并運行在 Java 虛擬機中的程式提供了一個進行除錯的標準機制,使用 SourccDcbugExtcnsion 屬性就可以用于存盤這個標準所新加入的除錯資訊 49.0
    BootstrapMethods ClassFile JDK1.7 新增的屬性,用于保存 invokedynamic 指令參考的引導方法限定符 51.0
    ConstantValue field_info final 關鍵字定義的常量值 45.3
    Code method_info Java 代碼編譯成的位元組碼指令 45.3
    Exceptions method_info 方法拋出的例外 45.3
    RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations method_info JDK5 中新增的屬性,作用于方法引數 RuntimeVisibleParameterAnnotations屬性指明哪些注解是運行時可見;RuntimeInvisibleAnnotations`屬性指明哪里注解是運行時不可見的 49.0
    AnnotationDefault method_info JDK1.5 中新增的屬性,用于記錄注解類元素的默認值 49.0
    MethodParameters method_info MethodParameters 屬性記錄方法的形式引數的資訊,比如方法名稱, 52.0
    Synthetic ClassFile, field_info, method_info 標識方法或欄位為編譯器自動生成的 45.3
    Deprecated ClassFile, field_info, method_info 被宣告為 Deprecated 的方法和欄位 45.3
    Signature ClassFile, field_info, method_info 記錄類,介面,建構式,方法或欄位的簽名 49.0
    RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations ClassFile, field_info, method_info JDK5 中新增的屬性,為動態注解提供支持,RuntimeVisibleAnnotations屬性指明哪些注解是運行時可見;RuntimeInvisibleAnnotations屬性指明哪里注解是運行時不可見的 49.0
    LineNumberTable Code LineNumberTable 屬性表存放方法的行號資訊 45.3
    LocalVariableTable Code LocalVariableTable 屬性表中存放方法的區域變數資訊 45.3
    LocalVariableTypeTable Code JDK 1.5 中新增的屈件,它使用特征簽名代替描述符,是為了引入泛型語法之后能描述泛型引數化型別而添加 49.0
    StackMapTable Code JDKL6 中新增的屬性.供新的型別檢查驗證器 (Type Checker)檢查和處理目標方法的后部變數和運算元堆疊所需要的型別是否匹配 50.0
    RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations ClassFile, field_info, method_info, Code jdk8 新增屬性
    RuntimeVisibleTypeAnnotations:運行時可見型別注解
    RuntimeInvisibleTypeAnnotations:運行時不可見型別注解
    52.0
  • Code 屬性

    Java 程式方法體中的代碼經過 Javac 編譯器處理后,最終成為位元組碼指令存盤在 Code 屬性內,注意并不是所有方法表都存在 Code 屬性,例如,介面和抽象類中的方法就不存在 Code 屬性,

  • Code 屬性格式定義

    Code_attribute {
        u2 attribute_name_index;  //指向常量CONSTANT_UTF8_info的索引,常量固定值為Code
        u4 attribute_length;
        u2 max_stack;   //運算元堆疊
        u2 max_locals;  //區域變數表所需的存盤空間
    
        //位元組碼長度,最大值可達2^32-1, 但是虛擬機限制了一個方法不允許超過65535條位元組碼指令
        //即使用了u2 的長度,超出這個限制會導致編譯失敗
        u4 code_length;
        u1 code[code_length]; //位元組碼指令的子節流
        u2 exception_table_length;
        {   u2 start_pc;
            u2 end_pc;
            u2 handler_pc;
            u2 catch_type;
        } exception_table[exception_table_length];
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }
    

二、位元組碼指令

2.1 加載和存盤指令

加載和存盤指令用于將資料在堆疊幀中的區域變數表與運算元堆疊之間傳輸,

  • 將區域變數加載到運算元堆疊

    // i  代表對int 操作
    // l  代表對long 操作
    // f 代表對float 操作
    // d 代表對double 操作
    // a 代表對參考reference 操作
    // iload_<n>  代表一組指令,iload_0、iload_1、iload_2、iload_3等指令
    iload
    iload_<n>
    lload
    lload_<n>
    fload
    fload_<n>
    dload
    dload_<n>
    aload
    aload_<n>
    
  • 將數值從運算元堆疊存盤到區域變數表

    istore
    istore_<n>
    lstore
    lstore_<n>
    fstore
    fstore_<n>
    dstore
    dstore_<n>
    astore
    astore_<n>
    
  • 將常量加載到運算元堆疊

    bipush
    sipush
    ldc
    ldc_w
    ldc2_w
    aconst_null
    iconst_ml
    iconst_<i>
    lconst_<l>
    fconst_<f>
    dconst_<d>
    
  • 擴充區域變數表的訪問索引的指令:wide

2.2 運算指令

相關指令
  • 加法指令

    iadd、ladd、fadd、dadd
    
  • 減法指令

    isub、 lsub、 fsub、 dsub
    
  • 乘法指令

    imul、 lmul、 fmul、 dmul
    
  • 除法指令

    idiv、 ldiv、 fdiv、 ddiv
    
  • 求余指令

     irem、 lrem、 frem、 drem
    
  • 取反指令

    ineg、 lneg、 fneg、 dneg
    
  • 位移指令

    ishl、 isbr、 iusbr、 lsbl、 lshr、 lushr
    
  • 按位或指令

    ior、 lor
    
  • 按位與指令

    iand、 land
    
  • 按位異或指令

    ixor、 lxor
    
  • 區域變數自增指令

    iinc
    
  • 比較指令

    dcmpg、 dcmpl、 fcmpg、 fcmpl、 lcmp
    
注意
  • 只有當除法指令和求余指令遇到除數為零時,虛擬機會拋出 ArithmeticException 例外
  • Java 在處理浮點數運算時,不會拋出任何運行例外(Java 語言的例外)
  • 當一個操作產生溢位時,將使用有符號的無窮大表示,如果某個操作結果沒有明確的數學定義的話,將會使用 NaN 表示
  • 所有使用 NaN 值作為運算元的算術操作,結果都回傳 NaN
double a = 1;
double b = a / 0;  //不會報錯,結果Infinity

double a = 0.0;
double b = a / 0.0; //不會報錯,結果NaN

2.3 型別轉換指令

型別轉換指令可以將兩種不同的數值型別進行互相轉換,一般用于用戶代碼中的顯示型別轉換操作,隱式型別轉換不同轉換指令,虛擬機直接支持,

  • 顯示型別轉換指令

    i2b  int 轉換byte
    i2c  int 轉換char
    i2s	 int 轉換short
    l2i  long 轉換 int
    f2i  float 轉換 int
    f2l  float 轉換 long
    d2i  double 轉換 int
    d2l  double 轉換 long
    d2f  double 轉換 float
    
  • 轉換規則

    • 如果浮點值是 NaN, 那轉換結果就是 int 或者 long 型別的 0
    • 如果浮點值不是無窮大的話,浮點值使用 IEEE 754 的向零舍入模式去整,獲取整數值 v,如果 v 在目標型別 T(int 或 long) 的標識表示范圍之內,那轉換結果就是 v,
    • 否則,將根據 v 的符號,轉換為 T 所能表示的最大或最小正數,
    double nan = 0.0 / 0.0;
    int a = (int) nan;
    System.out.println(a);  //0
    
    float b = (float) nan;
    System.out.println(b); //NaN
    

2.4 物件創建與訪問指令

  • 創建類實體指令

    new
    
  • 創建陣列指令

    newarray
    anewarray
    multianewarray
    
  • 訪問類欄位 和 實體欄位

    getfield
    putfield
    
    getstatic
    putstatic
    
  • 加載陣列元素到運算元堆疊

    baload  //byte陣列
    caload  //char陣列
    saload  //short陣列
    iaload  //int陣列
    laload //long 陣列
    faload //float 陣列
    daload //double 陣列
    aaload //物件陣列
    
  • 將運算元堆疊存盤到陣列元素中

    bastore
    castore
    sastore
    iastore
    lastore
    fastore
    dastore
    aastore
    
  • 獲取陣列長度

    arraylength
    
  • 檢查類實體型別的指令

    instanceof
    checkcast
    

2.5 運算元堆疊的管理指令

  • 出堆疊指令

    pop
    pop2 //出堆疊2個元素
    
  • 復制堆疊頂一個或者兩個數值并復制或雙份的復制值重新壓入堆疊頂

    dup
    dup2
    dup_x1
    dup2_x1
    dup_x2
    dup2_x2
    
  • 將堆疊最頂端的兩個數值互換

    swap
    

2.6 控制轉移指令

  • 條件分支

    ifeq
    iflt
    ifle
    ifne
    ifge
    ifnull
    ifnonull
    if_icmpeq  比較堆疊頂兩個int型別數值的大小 ,當前者  等于  后者時,跳轉
    if_icmpne
    if_icmplt
    if_icmpgt
    if_icmple
    if_icmpge
    if_acmpeq
    if_acmpne
    
  • 復合條件分支

    tableswitch   switch 條件跳轉 case值連續
    lookupswitch  witch 條件跳轉 case值不連續
    
  • 無條件分支

    goto 無條件跳轉
    goto_w 無條件跳轉  寬索引
    jsr   SE6之前 finally字句使用 跳轉到指定16位的offset,并將jsr下一條指令地址壓入堆疊頂
    jsr_w SE6之前 同上  寬索引
    ret  SE6之前回傳由指定的區域變數所給出的指令地址(一般配合jsr  jsr_w使用)
    w同區域變數的寬索引含義
    

2.7 方法呼叫和回傳指令

  • 方法呼叫指令

    
    invokevirtual: 呼叫物件實體方法
    invokeinterface 呼叫介面方法
    invokespecial 呼叫一些需要特需處理的實體方法,包括實體初始化方法、私有方法、父類方法
    invokestatic  呼叫類方法
    invokedynamic  在運行時動態決議出呼叫點限定符所參考的方法,并執行
    
  • 回傳指令

    ireturn
    lreturn
    freturn
    dreturn
    areturn
    return 宣告為void 的方法
    

2.8 例外處理指令

athrow  顯示拋出例外

2.9 同步指令

Java 虛擬機可以支持方法級別的同步和方法內部一段指令序列的同步,這兩種同步結構都使用管理(Monitor)來支持,

  • 方法級別的同步是由方法表結構中 ACC_SYNCHRONIZED 訪問標識來處理

  • 方法內部一段指令序列的同步

    monitorenter  獲取鎖,進入代碼塊
    monitorexit   釋放鎖,必須與monitorenter成對出現
    
  • 原始碼

    public class SynchronizedInstruction {
        private Object lock=new Object();
        void onlyMe(Object lock){
            synchronized (lock){
                //doSomething
            }
        }
    }
    
  • 反匯編

    Compiled from "SynchronizedInstruction.java"
    public class cn.hdj.jvm.bytecode.SynchronizedInstruction {
      private java.lang.Object lock;
      public cn.hdj.jvm.bytecode.SynchronizedInstruction();
      void onlyMe(java.lang.Object);
    }
    Classfile /home/hdj/IDEA/Java-Learning/src/main/java/cn/hdj/jvm/bytecode/SynchronizedInstruction.class
      Last modified 2021-3-20; size 488 bytes
      MD5 checksum 1f6db0fa955b6d719018d2ea50e1e910
      Compiled from "SynchronizedInstruction.java"
    public class cn.hdj.jvm.bytecode.SynchronizedInstruction
      SourceFile: "SynchronizedInstruction.java"
      minor version: 0
      major version: 51
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #2.#19         //  java/lang/Object."<init>":()V
       #2 = Class              #20            //  java/lang/Object
       #3 = Fieldref           #4.#21         //  cn/hdj/jvm/bytecode/SynchronizedInstruction.lock:Ljava/lang/Object;
       #4 = Class              #22            //  cn/hdj/jvm/bytecode/SynchronizedInstruction
       #5 = Utf8               lock
       #6 = Utf8               Ljava/lang/Object;
       #7 = Utf8               <init>
       #8 = Utf8               ()V
       #9 = Utf8               Code
      #10 = Utf8               LineNumberTable
      #11 = Utf8               onlyMe
      #12 = Utf8               (Ljava/lang/Object;)V
      #13 = Utf8               StackMapTable
      #14 = Class              #22            //  cn/hdj/jvm/bytecode/SynchronizedInstruction
      #15 = Class              #20            //  java/lang/Object
      #16 = Class              #23            //  java/lang/Throwable
      #17 = Utf8               SourceFile
      #18 = Utf8               SynchronizedInstruction.java
      #19 = NameAndType        #7:#8          //  "<init>":()V
      #20 = Utf8               java/lang/Object
      #21 = NameAndType        #5:#6          //  lock:Ljava/lang/Object;
      #22 = Utf8               cn/hdj/jvm/bytecode/SynchronizedInstruction
      #23 = Utf8               java/lang/Throwable
    {
      private java.lang.Object lock;
        flags: ACC_PRIVATE
    
      public cn.hdj.jvm.bytecode.SynchronizedInstruction();
        flags: ACC_PUBLIC
        Code:
          stack=3, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: aload_0
             5: new           #2                  // class java/lang/Object
             8: dup
             9: invokespecial #1                  // Method java/lang/Object."<init>":()V
            12: putfield      #3                  // Field lock:Ljava/lang/Object;
            15: return
          LineNumberTable:
            line 8: 0
            line 9: 4
    
      void onlyMe(java.lang.Object);
        flags:
        Code:
          stack=2, locals=4, args_size=2
             0: aload_1       //將lock物件入堆疊
             1: dup           //復制堆疊頂元素
             2: astore_2      //將堆疊頂元素存盤到區域變數表Slot2中
             3: monitorenter  //以lock物件為鎖,開始同步
             4: aload_2       //將區域變數表Slot2中元素入堆疊
             5: monitorexit   //退出同步
             6: goto          14  //程式正常結束,跳轉到14回傳
             9: astore_3      //從這步開始是例外路徑,開下面的Exception table
            10: aload_2       //將區域變數表Slot2中元素入堆疊
            11: monitorexit   //退出同步
            12: aload_3       //將區域變數表Slot3中元素(例外物件)入堆疊
            13: athrow        //把例外物件重新拋出個onlyMe方法呼叫者
            14: return        //方法回傳
          Exception table:
             from    to  target type
                 4     6     9   any
                 9    12     9   any
          LineNumberTable:
            line 11: 0
            line 13: 4
            line 14: 14
          StackMapTable: number_of_entries = 2
               frame_type = 255 /* full_frame */
              offset_delta = 9
              locals = [ class cn/hdj/jvm/bytecode/SynchronizedInstruction, class java/lang/Object, class java/lang/Object ]
              stack = [ class java/lang/Throwable ]
               frame_type = 250 /* chop */
              offset_delta = 4
    
    }
    
    

三、例子決議

  • 代碼
public class DemoDynamic {
    public static void foo() {
        int a = 1;
        int b = 2;
        int c = (a + b) * 5;
    }
}
  • javap 命令(也可以使用 IDEA 查看位元組碼工具:jclasslib)

    javac -g -encoding utf-8 DemoDynamic.java
    javap -verbose -c .\DemoDynamic.class >  .\DemoDynamic.javap
    
  • 位元組檔案

    Classfile /D:/IDEA/Java-Learning/src/main/java/cn/hdj/jvm/bytecode/DemoDynamic.class
      Last modified 2020-10-17; size 419 bytes
      MD5 checksum 0242e2d86e94eb62d302f5a034336416
      Compiled from "DemoDynamic.java"
    public class cn.hdj.jvm.bytecode.DemoDynamic
      minor version: 0  //版本號
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER  //訪問識別符號
    Constant pool:   //常量池
       #1 = Methodref          #3.#18         // java/lang/Object."<init>":()V
       #2 = Class              #19            // cn/hdj/jvm/bytecode/DemoDynamic
       #3 = Class              #20            // java/lang/Object
       #4 = Utf8               <init>
       #5 = Utf8               ()V
       #6 = Utf8               Code
       #7 = Utf8               LineNumberTable
       #8 = Utf8               LocalVariableTable
       #9 = Utf8               this
      #10 = Utf8               Lcn/hdj/jvm/bytecode/DemoDynamic;
      #11 = Utf8               foo
      #12 = Utf8               a
      #13 = Utf8               I
      #14 = Utf8               b
      #15 = Utf8               c
      #16 = Utf8               SourceFile
      #17 = Utf8               DemoDynamic.java
      #18 = NameAndType        #4:#5          // "<init>":()V
      #19 = Utf8               cn/hdj/jvm/bytecode/DemoDynamic
      #20 = Utf8               java/lang/Object
    {
      public cn.hdj.jvm.bytecode.DemoDynamic(); //默認的構造方法
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
        //堆疊容量1 , 區域變數表容量1, 引數個數1(因為每個實體方法都會有一個隱藏引數this)
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 6: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   Lcn/hdj/jvm/bytecode/DemoDynamic;
    
      public static void foo();  //foo()    方法
        descriptor: ()V
        flags: ACC_PUBLIC, ACC_STATIC  //識別符號,public static
        Code:  //方法表中Code 屬性
          stack=2, locals=3, args_size=0  //堆疊容量2 , 區域變數表容量3, 引數個數0
             0: iconst_1  //  將常量值1入堆疊->  堆疊1=1
             1: istore_0  //  將堆疊頂元素存盤到區域變數表Slot1位置  -> 區域0=1
             2: iconst_2  //  將常量值2入堆疊 ->  堆疊1=2
             3: istore_1  //  將堆疊頂元素存盤到區域變數表Slot2位置    ->  區域1=2
             4: iload_0   //  將區域變數表Slot1中元素入堆疊
             5: iload_1     // 將區域變數表Slot2中元素入堆疊
             6: iadd        // 執行相加操作, 1+2 = 3, 入堆疊
             7: iconst_5    // 將常量值5入堆疊
             8: imul        // 執行相乘操作,3*5=15,入堆疊
             9: istore_2    // 將堆疊頂元素存盤到區域變數表Slot2位置-> 區域2=15
            10: return    //回傳
          LineNumberTable: //行數表
            line 9: 0
            line 10: 2
            line 11: 4
            line 12: 10
          LocalVariableTable:  //區域變數表
            Start  Length  Slot  Name   Signature
                2       9     0     a   I
                4       7     1     b   I
               10       1     2     c   I
    }
    SourceFile: "DemoDynamic.java"
    
    

    1602932223498-945875c1-116c-425e-9ba7-17ff982d10e2

四、位元組碼增強

具體詳情看 位元組碼增強技術探索,這里只簡單列出相關工具及使用場景,

12e1964581f38f04488dfc6d2f84f003110966

4.1 ASM

對于需要手動操縱位元組碼的需求,可以使用 ASM,它可以直接生產 .class 位元組碼檔案,也可以在類被加載入 JVM 之前動態修改類行為

3c40b90c6d92499ad4c708162095fe3029983

  • ASM 工具 輔助工具
    • IDEA 插件 ASM ByteCode Outline,用于查看類中的代碼對應的 ASM 寫法

4.2   Javassist

利用 Javassist 實作位元組碼增強時,可以無須關注位元組碼刻板的結構,其優點就在于編程簡單,直接使用 java 編碼的形式,而不需要了解虛擬機指令,就能動態改變類的結構或者動態生成類,

4.3 Instrument

instrument 是 JVM 提供的一個可以修改已加載類的類別庫,專門為 Java 語言撰寫的插樁服務提供支持,它需要依賴 JVMTI 的 Attach API 機制實作,注意:ASM 和 Javassist 操作位元組碼庫只能在類加載前對類進行強化,

4.5 位元組碼增強技術使用場景

  • AOP 面向切面編程

  • 熱部署:不部署服務而對線上服務做修改,可以做打點、增加日志等操作,

  • Mock:測驗時候對某些服務做 Mock,

  • 性能診斷工具:比如 bTrace 就是利用 Instrument,實作無侵入地跟蹤一個正在運行的 JVM,監控到類和方法級別的狀態資訊,

參考

  • 《深入了解 Java 虛擬機 Java 高級特性和最佳實踐》
  • https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
  • 虛擬機指令 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5
  • https://www.cnblogs.com/noteless/p/9556928.html
  • 位元組碼增強技術探索 https://tech.meituan.com/2019/09/05/java-bytecode-enhancement.html
  • 輕松看懂 Java 位元組碼 https://juejin.im/post/6844903588716609543

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/270720.html

標籤:其他

上一篇:Kindle使用技巧

下一篇:一種資料選擇偏差下的去相關聚類方法

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more