Method Area(Non-Heap)方法区
方法区是所有线程共享的内存区域,用于存储已加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
方法区包含运行时常量池,Class 文件的各种字面量和符号引用,在类加载后会存入到运行时常量池中。直接引用也会存储在运行时常量池。除了类加载阶段,运行时常量也可以动态加入,比如String的 intern()方法;
其实在很久以前,是不存在永久代的。当时永久代与年老代都存放在一起,里面包含了JAVA类的实例信息以及类信息。但是后来发现,对于类信息的卸载几乎很少发生,因此便将二者分离开来
数据对象
- 已加载类信息
- 该类型的全限定名如java.io.FileOutputStream
- 该类型的直接超类的全限定名如java.io.OutputStream
- 该类型是类类型还是接口类型
- 该类型的访问修饰符(public、abstract、final)
- 任何直接超接口的全限定名的有序列表如java.io.Closeable, java.io.Flushable
- 指向Class类的引用
- 字段和方法数据
- 字段信息:对类型中声明的每个字段
- 方法信息
- 构造函数和普通方法的字节码内容
- 接口初始化时需要用到的特殊方法
- 运行时常量池:类和接口的全限定名、字段的名称和描述符、基本数据类型的直接数值(final)等
- 静态变量:静态变量而不是放在堆里面,所以静态属于类,不属于对象
- 即时编译器编译后的代码
- 指向ClassLoader类的引用
- 方法表:为了能快速定位到类型中的某个方法,JVM对每个装载的类型都会建立一个方法表,用于存储该类型对象可以调用的方法的直接引用,这些方法就包括从超类中继承来的而这张表与Java动态绑定机制的实现是密切相关的
注意
- JDK1.7的HotSpot已经把放在永久代的字符串常量池移出
- JDK1.8已将PermGen从Heap中移除
- 特别说明:java类中所有public和protected的实例方法都采用动态绑定机制,所有私有方法、静态方法、构造器及初始化方法<clinit>都是采用静态绑定机制。而使用动态绑定机制的时候会用到方法表,静态绑定时并不会用到
知识点
- 如果没有显式要求不对方法区进行内存回收,GC回收目标仅针对方法区中的常量池和类型卸载;
- JAVA虚拟机规范对方法区的限制非常宽松,除了和JAVA堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集;
- HotSpot虚拟机把GC分代收集扩展至方法区,所以在HotSpot可以称它为永久代(Permanent Generation)