深入学习java虚拟机》--笔记1

来源:互联网 发布:手机账本软件 编辑:程序博客网 时间:2024/05/16 01:10
 
这是张老师要求我们近期要读的一本书,现把主要知识点做个笔记:

  (1) 当JAVA虚拟机运行一个程序时,它需要内存来存储许多东西,例如,字节码,从已装载的的class文件中得到其他的信息,程序创建的对象、传递给方法的参数、返回值、局部变量,以及运算的中间结果等等,java虚拟机把这些东西都组织到几个“运行时数据区”中,便于管理。

  (2) 运行时数据区-是由程序中所有线程共享的,还有一些则只由一个线程拥有,每个Java虚拟机实例都由一个方法区以及一个堆,他们是由该虚拟机实例中所有线程共享的。当虚拟机装载一个class文件时,它会给这个class文件包含的二进制数据中解析类型信息。然后把这个些类型信息(后面会提到)放到方法区中。当程序运行时,虚拟机会把所有该程序在运行时创建的对象都放到堆中。

    (3)JAVA栈--由许多栈帧或说帧组成,一个帧包含一个JAVA方法的调用的状态。当线程调用一个方法时,虚拟机就压入一个新的帧到该线程的JAVA栈中,当该方法返回时,这个帧就被从JAVA栈中弹出并抛弃.

    (4)JAVA虚拟机是通过某些数据类型来执行计算的。数据类型分为:基本类型和引用类型
    基本类型---此类型变量持有原始值,即真正的原始数据
    引用类型---此类型变量持有引用值,即对某个对象的引用,而不是该对象本身。

   (5)类型信息:对每个装载的类型,虚拟机都会在方法区中存储以下数据信息..
   * 这个类型的全限定名。
   * 这个类型的直接超类的全限定名(除非这个类型是java.lang.Object,它没有超类)
   * 这个类型时类类型还是接口类型
   * 这个类型的访问修饰符(pulbic、abstract或final的某个子集)
   * 任何直接超接的全限定名的有序列表
   所谓的全限定名 由类所属包的名称加一个“ .”再加上类名组成。如Object类的全限定名为java.lang.Obeject
  
    除了上面的基本类型信息外,虚拟机还得为每个装载的类型存储以下信息:
    * 该类型的常量池 (就是该类型所用常量的一个有序集合)
    * 字段信息   (即对类型中声明的每个字段,包括--字段名、字段类型、字段的修饰符(public、private..))
    * 方法信息  (和字段一样,包括--方法名、返回类型(如void)、方法的修饰符、方法的字节码、操作数栈等)
    * 除常量以外的所有类(静态)变量 (此为所有类实例所共享,可以被访问)
    * 一个到类ClassLoader的引用
    * 一个到Class类的引用
       =>给出一个指向Class对象的引用,就可以通过Class类中定义的方法来找出这个类型的相关信息。如果看到这些
方法,会很快意识到,Class类使得运行的程序可以访问方法区中保存的信息。
下面时Class类中声明的方法:
     public String getName(); //返回类型的全限定名
     public Class getSuperClass(); //返回类型的直接超类的Class实例,若已是超类则返回Null,如Obeject类
     public boolen isInterface(); //判断是否是接口
     public Class[] getInterfaces();
     public ClassLoader getClassLoader();
(6)下面举例展示下虚拟机如何使用方法去中的信息:
   class Lava{
        private int speed=5;
         void flow(){
           }
        }
    class Volcano{
      public static void main(string[] args)
             {
                Lava lava=new Lava();
                 lava.flow();
               }
          }

现在讲述下它时如何运行的:
我们知道一般代码都是从main这个入口函数开始执行的,由于它在Volcano类中,所以
  一、虚拟机运行时会读入class文件,也就是“Volcano.class”,然后它会从导入到Class文件里的二进制数据中提取类型信息文件并放到方法区中。通过执行保存在这个方法区的字节码,虚拟机就开始执行main(),在执行时,它会一直持有指向当前类的常量池(一个数据结构)的指针。
  二、在main() 里面 发现时个LAVA 类的符号引用(lava),然后就检查方法区,看Lava类是否被加载了.
  三、当虚拟机发现还没装载过名为“Lava”类时,它就开始寻找并装载文件“Lava.class”,并把读入的二进制数据中提取的类型信息也放到方法区中。
  四、接着,虚拟机一个指向方法区Lava类数据的指针来替换常量池第一项(就是前面遇到的字符串“Lava”)。这个替换的过程称为--常量池解析,即把常量池中的符号引用改为直接引用。
  五、现在虚拟机就需要为一个新的Lava对象分配内存。此时,它有需要方法区中的信息。然后虚拟机就用之前的那个指针来访问类型信息,找出其其中记录的这样一条信息:一个Lava对象需要分配多少堆空间。
  六、当虚拟机确定了一个Lava对象的大小后,它就在堆上分配这么大的空间,并把实例的变量speed默认初始化为0.
  七、当生成的Lava对象的引用(即lava)压到栈中时,main()的第一条指令(也就是实例化个lava对象)也就完成的。接下来就是这个引用lava 调用代码(该代码把speed变量初始化为正确的初始值5)。另一条指令将用这个引用调用flow()方法。

  JAVA虚拟机总能够通过存储于方法区的类型信息来确定一个对象需要多少内存,但是某个特定对象事实上需要多少内存,时跟特定的实现相关的。

(7)