ming莫 发表于 2017-12-26 22:52

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


# Java虚拟机内存区域分布和字节码简析
## 虚拟机内存区域
![](http://ww1.sinaimg.cn/large/b1b3510fgy1fmujpu6lmuj20w00jcwfb.jpg)

![](http://ww1.sinaimg.cn/large/b1b3510fgy1fmujmwnjtlj20w00i0wey.jpg)

## 解读字节码文件
测试类代码:
```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";
                }
        }
}
```

控制台命令:
```cmd
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)
![](http://ww1.sinaimg.cn/large/b1b3510fgy1fmu779vk4pj20q80beta2.jpg)

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

### 构造方法解析
![](http://ww1.sinaimg.cn/large/b1b3510fgy1fmu7f05yorj20nj0f3aaz.jpg)

#### 方法属性信息:
- **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**,这个指令用来调用对象的特殊方法,这里的特殊方法<init>是这个对象的**构造方法**

**上面两局结合起来就是从局部变量表中取出第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赋值**

VioletKiss 发表于 2017-12-28 09:54

Mark,先收藏了

seedhk 发表于 2017-12-28 09:48

好东西,谢谢楼主

ming莫 发表于 2017-12-27 15:46

Tisrop 发表于 2017-12-27 08:59
初学java的我看的一头雾水

{:301_998:}先看着先,以后慢慢就理解了

Tisrop 发表于 2017-12-27 08:59

初学java的我看的一头雾水

五五66 发表于 2017-12-27 08:50

用java的程序员必须足够的了解他的虚拟机

chen1234 发表于 2017-12-27 07:42

页: [1]
查看完整版本: Java虚拟机内存区域分布和字节码简析