JVM的方法区以及JVM运行java文件的过程

本文整合自http://blog.csdn.net/tuhuolong/article/details/5951589

JVM中的方法区主要存放类的信息等,JVM中的类信息也会被GC,满足以下条件的类就会被GC:

1、该类的堆中所有的实例都被回收。

2、加载该类的类加载器都被回收。

3、该类所对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射机制访问该类的方法。(反射机制比较复杂,以后在好好研究)

类信息:

1、类的完整有效名(包名+类名中间用斜杠隔开,例如java/lang/Object)。

2、直接父类的完整有效名。

3、类的修饰符(public等)。

4、类的直接接口的一个有序列表。

5、类的常量池:保存符号引用及基本数据类型和String类型的常量

6、成员域信息:

     域名、域类、域修饰符,例如public String x,域名为x,域类为String,域修饰词为public。

7、方法信息:

     方法名、方法的返回类型、方法的参数列表(包括顺序)方法的修饰符、操作数栈和局部变量表的大小、异常表。

     当我们执行一个方法时,会找到方法区中该方法的信息进行比对,因为方法的参数列表是有序的,所以我们可以重载函数。

8、除了常量以外的所有静态变量。

9、是接口还是类。

10、对类加载器的引用,若一个类是通过用户类加载器加载的,则会保存该加载器的引用,保存在方法区中。

11、对Class类的引用,JVM为每个加载的类都创建一个java.lang.Class的实例,我的理解是这个值相当于索引,帮助我们找到方法区中对应的类信息。

        该实例可以通过Class.forName(类名或接口名)获得,调用该函数时,若还未加载该类,JVM会尝试加载对应类,若无法加载该类,则会抛出ClassNotFoundException。通过该实例,我们可以获取存储在方法区中的类信息,相关方法如下:

public String getName(); //返回类的完整名
public Class getSuperClass();// 返回父类的完整名
public boolean isInterface(); //是否是接口
public Class[] getInterfaces(); //获取接口列表
public ClassLoader getClassLoader();// 获取类加载器的引用

方法表

方法表是一组对类实例方法的直接引用,JVM可以通过方法表快速激活实例方法。

下面通过一个实例来了解一下JVM运行java的过程

下面是代码:

  class Lava { 
    private int speed = 5; 
    void flow() { 
    } 
} 

class Volcano { 
    public static void main(String[] args) { 
        Lava lava = new Lava(); 
        lava.flow(); 
    } 
} 
JVM通过某种方式加载对应类的class文件(在windows命令行环境下,我们输入java+类名,就是告诉JVM从当前文件下加载该类,windows命令行要先进入到对应文件后执行java指令,否则JVM会误认为java后面的带路径的类名为类名),JVM通过解析方法区的字节码得到main函数的位置,接着执行main函数,在main函数的第一行,我们new了一个Lava, jvm使用指向Volcano常量池的指针找到Lava(查看反编译代码,可以看到指令的后面有一个索引号,JVM根据该索引号来进行查找),发现是一个对 Lava类的符号引用,然后它就检查方法区看lava是否已经被加载了,发现还没有加载该类,于是,JVM开始加载Lava类,从class文件中抽出类信息放在方法区中, 于是 jvm以一个直接指向方法区lava类的指针替换了常量池中该类的符号引用。以后就可以用这个指针快速的找到lava类了。而这个替换过程称为常量池解析(constant pool resolution),根据该指针,JVM找到方法区中存储的类信息,得知需要多少堆内存空间,接着执行方法。


你可能感兴趣的:(JVM的方法区以及JVM运行java文件的过程)