Java虚拟机内存区域分布和字节码简析

Java虚拟机内存区域分布和字节码简析

虚拟机内存区域

解读字节码文件

测试类代码:

package com.momingqi;

public class Custom {

    String m1 = "I love you";
    String m2 = "I like you";
    int i2 = 1024;
    short i3 = 10;

    public static final String haha = "hahahaha";

    public static void say() {
        System.out.println(Custom.haha);
    }

    public String getString(String key) {
        if (key.equals("m1"))
            return m1;
        else {
            return "what the fuck";
        }
    }
}

控制台命令:

javac Custom.java
javap -verbose Custom.class

控制台输出的字节码

C:\Users\mingC\Desktop>javap -verbose Custom.class
Classfile /C:/Users/mingC/Desktop/Custom.class
  Last modified 2017-12-26; size 862 bytes
  MD5 checksum 1b8103d38f9c253db7ace7647ab688d4
  Compiled from "Custom.java"
public class com.momingqi.Custom
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #15.#35        // java/lang/Object."<init>":()V
   #2 = String             #36            // I love you
   #3 = Fieldref           #9.#37         // com/momingqi/Custom.m1:Ljava/lang/String;
   #4 = String             #38            // I like you
   #5 = Fieldref           #9.#39         // com/momingqi/Custom.m2:Ljava/lang/String;
   #6 = Fieldref           #9.#40         // com/momingqi/Custom.i2:I
   #7 = Fieldref           #9.#41         // com/momingqi/Custom.i3:S
   #8 = Fieldref           #42.#43        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = Class              #44            // com/momingqi/Custom
  #10 = String             #45            // hahahaha
  #11 = Methodref          #46.#47        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #12 = String             #16            // m1
  #13 = Methodref          #48.#49        // java/lang/String.equals:(Ljava/lang/Object;)Z
  #14 = String             #50            // what the fuck
  #15 = Class              #51            // java/lang/Object
  #16 = Utf8               m1
  #17 = Utf8               Ljava/lang/String;
  #18 = Utf8               m2
  #19 = Utf8               i2
  #20 = Utf8               I
  #21 = Utf8               i3
  #22 = Utf8               S
  #23 = Utf8               haha
  #24 = Utf8               ConstantValue
  #25 = Utf8               <init>
  #26 = Utf8               ()V
  #27 = Utf8               Code
  #28 = Utf8               LineNumberTable
  #29 = Utf8               say
  #30 = Utf8               getString
  #31 = Utf8               (Ljava/lang/String;)Ljava/lang/String;
  #32 = Utf8               StackMapTable
  #33 = Utf8               SourceFile
  #34 = Utf8               Custom.java
  #35 = NameAndType        #25:#26        // "<init>":()V
  #36 = Utf8               I love you
  #37 = NameAndType        #16:#17        // m1:Ljava/lang/String;
  #38 = Utf8               I like you
  #39 = NameAndType        #18:#17        // m2:Ljava/lang/String;
  #40 = NameAndType        #19:#20        // i2:I
  #41 = NameAndType        #21:#22        // i3:S
  #42 = Class              #52            // java/lang/System
  #43 = NameAndType        #53:#54        // out:Ljava/io/PrintStream;
  #44 = Utf8               com/momingqi/Custom
  #45 = Utf8               hahahaha
  #46 = Class              #55            // java/io/PrintStream
  #47 = NameAndType        #56:#57        // println:(Ljava/lang/String;)V
  #48 = Class              #58            // java/lang/String
  #49 = NameAndType        #59:#60        // equals:(Ljava/lang/Object;)Z
  #50 = Utf8               what the fuck
  #51 = Utf8               java/lang/Object
  #52 = Utf8               java/lang/System
  #53 = Utf8               out
  #54 = Utf8               Ljava/io/PrintStream;
  #55 = Utf8               java/io/PrintStream
  #56 = Utf8               println
  #57 = Utf8               (Ljava/lang/String;)V
  #58 = Utf8               java/lang/String
  #59 = Utf8               equals
  #60 = Utf8               (Ljava/lang/Object;)Z
{
  java.lang.String m1;
    descriptor: Ljava/lang/String;
    flags:

  java.lang.String m2;
    descriptor: Ljava/lang/String;
    flags:

  int i2;
    descriptor: I
    flags:

  short i3;
    descriptor: S
    flags:

  public static final java.lang.String haha;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: String hahahaha

  public com.momingqi.Custom();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: ldc           #2                  // String I love you
         7: putfield      #3                  // Field m1:Ljava/lang/String;
        10: aload_0
        11: ldc           #4                  // String I like you
        13: putfield      #5                  // Field m2:Ljava/lang/String;
        16: aload_0
        17: sipush        1024
        20: putfield      #6                  // Field i2:I
        23: aload_0
        24: bipush        10
        26: putfield      #7                  // Field i3:S
        29: return
      LineNumberTable:
        line 3: 0
        line 5: 4
        line 6: 10
        line 7: 16
        line 8: 23

  public static void say();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #10                 // String hahahaha
         5: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 13: 0
        line 14: 8

  public java.lang.String getString(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ldc           #12                 // String m1
         3: invokevirtual #13                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
         6: ifeq          14
         9: aload_0
        10: getfield      #3                  // Field m1:Ljava/lang/String;
        13: areturn
        14: ldc           #14                 // String what the fuck
        16: areturn
      LineNumberTable:
        line 17: 0
        line 18: 9
        line 20: 14
      StackMapTable: number_of_entries = 1
        frame_type = 14 /* same */
}
SourceFile: "Custom.java"

首先看到字节码头几行是文件信息,包括编译版本、修饰符等。

下面分析字节码的常量池(Constant pool)

  • 用#号加数字的形式来表示一个常量
  • 常量之间可以相互引用
  • 这些常量包括:字段名称、方法名称、类名等等
  • 这些常量存放在方法区的运行时常量池

构造方法解析

方法属性信息:

  • stack=2,代表操作数栈的深度为2
  • locals=1,代表局部变量表的大小为1个slot(可以理解为一个32位数据),slot可以复用
  • args_size=1,代表参数数目,实例方法隐藏参数‘this’,所以这里参数大小为1

LineNumberTable

代表的是字节码行数(字节码的偏移量)和Java源码的对应关系,这不是必需的

方法体

0: aload_0
1: invokespecial #1                  // Method java/lang/Object."<init>":()V
  • 指令前面的数字代表字节码偏移量,可以忽略;
  • 带井号的是指令的参数
  • aload_0 代表将0号变量放入操作数栈中,在这里0号参数是“this”指令
  • 第一行调用指令invokespecial,这个指令用来调用对象的特殊方法,这里的特殊方法是这个对象的构造方法

上面两局结合起来就是从局部变量表中取出第0号变量,然后调用构造方法,而第0号变量就是这个构造方法的参数。

4: aload_0
5: ldc           #2                  // String I love you
7: putfield      #3                  // Field m1:Ljava/lang/String;
  • ldc是从运行时常量池中加载一个常量到操作数栈中
  • putfield是字面意思,给对象的字段赋值

上面代码的执行过程是:先加载局部变量表中第0号变量,在加载常量池中的字符串,然后调用方法putfield给字段m1赋值

猜你喜欢

转载自blog.csdn.net/mingc0758/article/details/78907495