Jvm内存分配(4)

下面的内容全部来自网络,基本无原创。只是学习笔记而已。

3.2.2 方法区的使用

为了显示jvm如何使用方法区中的信息,我们据一个例子,我们看下面这个类:

 

class Lava {
    private int speed = 5; // 5 kilometers per hour
    void flow() {
    }
}
class Volcano {
    public static void main(String[] args) {
        Lava lava = new Lava();
        lava.flow();
    }
}

 下面我们描述一下main()方法的第一条指令的字节码是如何被执行的。不同的jvm实现的差别很大,这里只是其中之一。

 

 

一下是以上代码的字节码。

 

public class Lava {
  
  // Field descriptor #6 I
  private int speed;
  
  // Method descriptor #8 ()V
  // Stack: 2, Locals: 1
  public Lava();
     0  aload_0 [this]
     1  invokespecial java.lang.Object() [10]
     4  aload_0 [this]
     5  iconst_5
     6  putfield Lava.speed : int [12]
     9  return
      Line numbers:
        [pc: 0, line: 1]
        [pc: 4, line: 3]
        [pc: 9, line: 1]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: Lava
  
  // Method descriptor #8 ()V
  // Stack: 0, Locals: 1
  void flow();
    0  return
      Line numbers:
        [pc: 0, line: 6]
      Local variable table:
        [pc: 0, pc: 1] local: this index: 0 type: Lava
}

 class Volcano {

  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  Volcano();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 9]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: Volcano
  
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 2, Locals: 2
  public static void main(java.lang.String[] args);
     0  new Lava [16]
     3  dup
     4  invokespecial Lava() [18]
     7  astore_1 [lava]
     8  aload_1 [lava]
     9  invokevirtual Lava.flow() : void [19]
    12  return
      Line numbers:
        [pc: 0, line: 11]
        [pc: 8, line: 12]
        [pc: 12, line: 13]
      Local variable table:
        [pc: 0, pc: 13] local: args index: 0 type: java.lang.String[]
        [pc: 8, pc: 13] local: lava index: 1 type: Lava
}

 1 为了运行这个程序,你以某种方式把“Volcano"传给了jvm有了这个名字,jvm找到了这个类文件(Volcano.class)并读入,它从类文件提取了类型信息并放在了方法区中

2 通过解析存在方法区中的字节码,jvm激活了main()方法,在执行时,jvm保持了一个指向当前(Volcano)常量池的指针。注意jvm在还没有加载Lava类的时候就已经开始执行了。正像大多数的jvm一样,不会等所有类都加载了以后才开始执行,它只会在需要的时候才加载。其实就是按需加载)

       这个符号引用仅仅是类lava的完整有效名”lava“。这里我们看到为了jvm能尽快从一个名称找到一个类,一个良好的数据结构是多么重要。这里jvm的实现者可以采用各种方法,如hash表,查找树等等。同样的算法可以用于Class类的forName()的实现

3 jvm发现还没有加载过一个称为"Lava"的类,它就开始查找并加载类文件"Lava.class"。它从类文件中抽取类型信息并放在了方法区中。

4 jvm于是以一个直接指向方法区lava类的指针替换了常量池第一项的符号引用。以后就可以用这个指针快速的找到lava类了。而这个替换过程称为常量池解析(constant pool resolution)。在这里我们替换的是一个native指针。

5 jvm终于开始为新的lava对象分配空间了。这次,jvm仍然需要方法区中的信息。它使用指向lava数据的指针(刚才指向volcano常量池第一项的指针)找到一个lava对象究竟需要多少空间。

jvm总能够从存储在方法区中的类型信息知道某类型对象需要的空间。但一个对象在不同的jvm中可能需要不同的空间,而且它的空间分布也是不同的。

6 一旦jvm知道了一个Lava对象所要的空间,它就在堆上分配这个空间并把这个实例的变量speed初始化为缺省值0。假如lava的父对象也有实例变量,则也会初始化。(晕 这个需要后面heap的知识)

7 当把新生成的lava对象的引用压到栈中,第一条指令也结束了。下面的指令利用这个引用激活java代码把speed变量设为初始值

8 另外一条指令会用这个引用激活

 

 

你可能感兴趣的:(jvm内存)