浅谈Java虚拟机

Java的体系结构包含四个独立但相关的技术:

   1,Java程序设计语言

   2,Java class文件格式

   3,Java应用程序编程接口(API)

   4,Java虚拟机


    其中,Java虚拟机就像一台抽象的计算机,其规范定义了每个Java虚拟机都必须实现的特性,当然也为每个特性的实现留下了许多实现的选择。Java虚拟机的主要任务是装载class文件并执行其中的字节码。


    Java虚拟机主要由两部分组成,一部分叫“类装载器”,另一个部分叫“执行引擎”。“类装载器”用于从程序和API中装载class文件(Java API中只有程序执行时需要的那些类才会被装载),而“执行引擎”则执行装载的字节码,在执行的过程中还可能通过JNI来调用操作系统本地方法。


    在虚拟机的内部,虚拟机的行为分别按照 子系统、内存区、数据类型以及指令这几个术语来描述的,这就组成了虚拟机内部抽象的体系结构。这样,我们可以将虚拟机近一步抽象的分为“类装载子系统”、运行时数据区“、”执行引擎“以及”本地方法接口“。”运行时数据区“是一块内存区域,用来存储从已装载的class文件中得到的其他信息、程序所创建的对象、传递给方法的参数、返回值、局部变量、运行的中间结果等。


    运行时数据区大体可分为:方法区、堆、java栈、PC寄存器和本地方法栈。当装载一个class文件时,会从class文件包含的二进制数据中解析类型信息,然后把这些类型信息放到方法区中,当运行的时候,会把程序创建的对象都放在堆中,所以方法区和堆都是线程共享的。


    当一个线程创建时,该线程会拥有属于自己的一个PC寄存器(程序计数器)以及一个Java栈,如果线程执行的是一个Java方法(非本地方法),那么寄存器的指总是指向下一条将被指向的指令,而它的栈则总是存储该线程中Java方法调用的状态(局部变量、传进来的参数、返回值以及计算的中间值等)。而本地方法调用的状态则是存存储在本地方法栈中,当然根据实现的不同,也有可能是在寄存器或者其他某些与特定实现相关的内存区中。


    通过上面的讲解,大家可以想想线程安全的问题。


    那么方法区中到底都存放了些什么信息呢?其实里面存放的都是一些类型信息,包括类变量(静态变量)也会被存在这里。对每个装载的类型,虚拟机都会在方法区中存储一下类型信息:

        1,这个类型的全限定名

        2,这个类型的直接超类的全限定名(除非是Object,无超类)

        3,这个类型是类类型还是接口类型

        4,这个类型的访问修饰符(public、abstract或final的某个子集)

        5,任何直接超接口的权限定名的有序列表

    以上列出的是存储的基本信息,除了这些信息外,还要存储以下的信息:

        6,被载入的类型的常量池

        7,字段信息

        8,方法信息

        9,除了常量以外的所有类变量

        10,一个到类ClassLoader的引用

        11,一个大Class类的引用


    “运行时常量池”或者叫“常量池”,它是方法区的一部分,在class文件中,包含了常量池的相关信息,用于存放编译期生成的各种字面量和符号引用。常量池就是该类型所用常量的一个有序集合,包括直接常量(string、integer、floating point常量)和对其他类型、字段和方法的符号引用。

    

    对于常量池这个概念,也许很多人都会觉得奇怪,搞不清这个的作用到底是啥。这里所指的“常量”可不等同与我们代码中所谓的常量,这里的常量就是一个类型中包含的固定不变的信息。首先,当我们将java源代码编译成一个class文件后,class文件中用字节码的形式保存了java源文件中所有的信息,例如我们定义的方法、属性等。  根据所保存的常量类型的不同个,常量池又被分为了不同的区域,这里大家提到最多的莫过于string常量区域。对于在源文件中定义的字符串字面量,例如:String name = "test" , 不论该变量是成员属性还是在方法中声明的局部变量,该值都会在class加载的时候保存在常量池的string类型常量区中。


    需要注意区分的是上面的方式和通过new创建的字符串的不同,例如:String name = new String("test") 。 这里其实会涉及到两个对象,一个是字符串字面量"test",该值同上面一样会在class文件加载 时候放入到string常量区域中,同时在运行的时候会在堆中创建一个对象(即开辟一个堆内存区域),并且从string常量区域中拷贝一份"test" 指来保存在堆上。 所以,这就是为什么我们在比较两个字符串相等的时候最好不要用等号“==”而要使用equals方法的原因。


    常量池就像一个词典,里面记录中程序运行过程中所需要的全部信息,这也就成为了Java动态链接的基础。


    接下来谈谈在开发中常常会用到的几个对JVM的配置。

        1,堆大小的配置

            堆的最小值配置参数:-Xms200M

            堆的最大值配置参数:-Xmx300M

            注:如果这两个参数配置一样大小,则可以避免堆的自动扩展。

        2,方法区大小的配置

            设置方法区的默认大小:-XX:PermSize=200M

            设置方法区的最大值:-XX:MaxPermSize=300M

        

            

        

    暂时就记录这么多了,以后有必要的时候再添加上来。


    



    


    


    





你可能感兴趣的:(java,jvm,虚拟机)