基本描述
- 方法区与Java heap一样,是线程共享的区域,需要注意同步问题。
该区域主要存储已被虚拟机加载的类的基本信息,比如,类的常量池、静态变量等。准确的说包括:类及其父类的全限定名(java.lang.Object没有父类)、类的类型(Class or Interface)、访问修饰符(public, abstract, final)、实现的接口的全限定名的列表、常量池、字段信息、方法信息、静态变量、ClassLoader引用、Class引用当虚拟机装载某个类型时,首先使用ClassLoader定位class文件,然后读入该二进制文件把它输入到虚拟机中。紧接着虚拟机提取其中的类型信息,并将这些信息存储到方法区。该类型中的类(静态)变量同样也存储在方法区中。
通过Class对象的getName、isInterface方法来获取信息时候,这些信息都来源于方法区
- 根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。调节大小使用-XX:PerSize和-XX:MaxPerSize
- 虚拟机规范把方法区描述为堆的一个逻辑部门,但是我们通常把他称为非堆;HotSpot采用持久代来实现方法区,并且可以进行回收。这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,但是效果不是很明显。
Java虚拟机规范对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。
持久代在新的jdk中已经被移除。
类型基本信息(Class类中提供相关方法)
- 这个类的全限定名:java.lang.String
- 这个类的直接超类全限定名,除Object外(没有超类)
- 类类型:接口还是类
- 这个类的访问修饰符(public、abstract或final的某个子集)
- 任何直接超接口的全限定名的有序列表
//返回类的全限定名
public string getName();
//返回类型的直接超类实例(object或者接口返回null)
public Class getSuperClass();
//判断该类型是否是接口
public boolean isInterface();
//返回一个Class对象数组,每个Class对象对应一个直接超类接口,如果该类型没有直接超接口,getInterfaces()返回一个0长度数组
public Class[] getInterfaces();
//返回该类型的ClassLoader对象的引用
public ClassLoader getClassLoader();
其他类信息
- 该类的常量池
- 字段信息
- 方法信息
- 除了常量以外的静态变量
- 一个到类ClassLoader的引用
每个类型被装载的时候,虚拟机必须跟踪它是由启动类装载器还是由用户自定义类装载器装载的。如果是用户自定义类装载器装载的,那么虚拟机必须在类型信息中存储对该类型装载器的引用。这是作为方法表中的类型数据的一部分保存的。
虚拟机会在动态连接期间使用这个信息。当某个类型引用另一个类型的时候,虚拟机会请求装载发起引用的类装载器来装载被引用的类型。这个动态连接的过程,对于虚拟机分离命名空间的方式也是至关重要的。为了能够正确执行动态连接以及维护多个命名空间,虚拟机需要在方法表中得知每个类都是哪个类装载器装载的。
- 一个到类Class的引用
对于每个被装载的类型(不管是类还是接口),虚拟机都会相应地为它在堆上创建一个java.lang.Class类的实例,而且虚拟机还必须以某种方式把这个实例和存储在方法区中的类型数据关联起来。
在程序中,可以使用指向Class对象的引用。Class类中的两个方法可以得到任何已装载的类的Class实例的引用。分别是Class.forName(“”)以及Class.getClass()。
给出一个Class对象的引用,就可以通过Class类中的定义的方法来找出这个类型的相关信息。如果查看这些方法会很快意思到,Class类使得运行程序可以访问方法区中保存的信息。
字段信息
对于类中声明的每一个字段,方法区必须保存下面的信息,除此之外这些字段在类或接口中声明的顺序也必须保存。
- 字段名
- 字段类型
- 字段的修饰符(public、private、protected、static、abstract、final、volatile、transient的某个子集)
方法信息(和字段信息一样保证顺序性)
- 方法名
- 方法的返回值(或者Void)
方法的修饰符(public、private、protected、static、abstract、final、native、synchronized的某个子集)
非抽象或者非本地的方法还需要保存:方法的字节码
- 操作数栈和该方法的栈帧中局部变量表的大小
- 异常表
常量池
常量池是该类所用常量的一个有序集合,包括直接常量(string、integer和floating point常量)和对其他类型、字段和方法的符号引用。