栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

深入JAVA虚拟机连载(三)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深入JAVA虚拟机连载(三)

方法区

        在java虚拟机中,关于被装载的类型信息存储在一个逻辑上被称为方法区的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件——一个线性二进制数据流——然后将它传输到虚拟机中,紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。该类型中的类(静态)变量同样也是存储在方法区中。

        当虚拟机运行java程序时,它会查找使用存储在方法区中的类型信息。设计者应当为类型信息的内部表示设计适当的数据结构,以尽可能在保持虚拟机小巧紧凑的同时加快程序的运行效率。java虚拟机的设计者可以根据目标平台的资源限制和需求,在空间和时间上做出权衡,选择什么样的数据结构和数据组织。

        由于所有线程都共享方法区,因此它们对方法区数据的访问必须被设计为线程安全的。

        方法区的大小不必是固定的,虚拟机可以根据应用的需要动态调整。同样,方法区也不必是连续的,方法区可以在一个堆中自由分配,虚拟机可以允许用户或程序员指定方法区的初始大小以及最小和最大尺寸等。

        方法区中存储以下类型信息:

1、这个类型的全限定名(比如java.lang.Object的全限定名是java/lang/Object)

2、这个类型的知己超类全限定名,除非这个类型java.lang.ObjectObject没有超类

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

4、这个类型的访问修饰符

5、任何直接超接口的全限定名的有序列表

        除了以上基本类型信息外,还存储以下信息:

        该类型的常量池,字段信息,方法信息,除了常量意外的所有类(静态)变量,一个类ClassLoader的引用。如果某个方法不是抽象的和本地的,还保存以下信息:方法的字节码,操作数栈和该方法的栈桢中的局部变量区的大小,异常表。

        当某个类型引用另一个类型的时候,虚拟机会请求装载发起引用类型的类装载器来装载被引用的类型。这个动态连接的过程,对于虚拟机分离命名空间的方式是至关重要的。为了能够正确地执行动态连接以及维护多个命名空间,虚拟机需要在方法表中得知每个类都是由哪个类装载器装载的。

        方法表:虚拟机对每个装载的非抽象类,都生成一个方法表,把它作为类信息的一部分保存在方法区。方法表是一个数组,它的元素是所有它的实例可能被调用的实例方法的直接引用,包括那些从超类继承过来的实例方法。运行时可以通过方法表快速搜寻在对象中调用的实例方法。

        方法区的使用示例:

class A{

private int a = 5;

public void test(){}

}

class B{

public static void main(String []args){

A a = new A();

a.test();

}

}

        要运行B程序,首先得以某种“依赖于实现的”方式告诉虚拟机B这个名字。之后,虚拟机将找到并读入相应class文件“B.class”,然后它会从导入的class文件里的二进制数据中提取类型信息并放到方法区中。通过执行保存在方法区中的字节码,虚拟机开始执行main()方法,在执行时,它会一直持有指向当前类(B类)的常量池(方法区中的一个数据结构)的指针。

        注意,虚拟机开始执行B类的main()方法的字节码时,尽快A类还没有被装载,但是和大多数虚拟机一样,它不会等到把程序中用到的所有类都装载后才开始运行程序,它只在需要时才装载想要的类。

        main()的第一条指令告知虚拟机为列在常量池第一项的类分配足够的内存。所以虚拟机使用执行B常量池的指针找到第一项,发现它是一个对A类的符号引用,然后它就检查方法区,看A类是否被装载了。

        这个符号引用仅仅是一个给出了类A的全限定名"A"的字符串。为了让虚拟机尽可能快地从一个名称找到类,设计者应当选择最佳的数据结构和算法,这个方法根据给定的全限定名返回class引用。

        当虚拟机发现还没有装载过名为“A”的类时,它就开始查找并装载“A.class”,并把从读入的二进制数据中提取的类型信息放在方法区中。

        紧接着,虚拟机以一个直接指向方法区A类数据的指针来替换常量池的第一项,以后就可以用这个指针来快速地访问A类了。这个替换的过程称为常量池解析,即把常量池的符号引用替换为直接引用。

        终于,虚拟机准备为一个新的A对象分配内存。此时,它又需要方法区中的信息。现在虚拟机用它的指针来访问A类型信息,找出其中记录的这样一个信息:一个A对象需要分配多少堆空间。

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

        当java虚拟机确定了一个A对象的大小后,它就在堆上分配这么大的空间,并把这个对象实例的变量a初始化为默认的初始值0 。

        当把新生成的A对象的引用压到栈中,main()方法的第一条指令也完成了。接下来的指令通过这个引用调用java代码,把a变量初始为正确的5,另外一条指令将用这个引用调用A对象引用的 test()方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/311015.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号