1 JVM(HotSpot)内存模型
上面这种图是HotSpot虚拟机的内存模型,本篇文章主要介绍方法区。
因为方法区在JDK1.7及其以前版本中的实现方式——永久带
在JKD8中被移除了。
至于其他部分不太了解的可以阅读这篇文章:http://blog.csdn.net/hylexus/article/details/53564865
2 官方对方法区的介绍
以下是《Java虚拟机规范(JavaSE7)》一书中对方法区的描述:
在 Java 虚拟机中,方法区( Method Area) 是可供各条线程共享
的运行时内存区域
。方法区与传统语言中的编译代码储存区( Storage Area Of Compiled Code)或者操作系统进程的正文段( Text egment)的作用非常类似,它存储了每一个类的结构信息
,例如运行时常量池( Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法( §2.9)。
方法区在虚拟机启动的时候被创建,虽然方法区是堆的逻辑组成部分
,但是简单的虚拟机实现可以选择在这个区域不实现垃圾收集。这个版本的 Java 虚拟机规范也不限定实现方法区的内存位置和编译代码的管理策略。方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。方法区在实际内存空间中可以是不连续的。
Java 虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段
如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个OutOfMemoryError
异常。
总之,就是用来存储类的描述信息——元数据的。它有一个别名叫做Non-Heap(非堆)。
3 常说的永久带和方法区是什么关系?
平时,说到永久带(PermGen space
)的时候往往将其和方法区不加区别。这么理解在一定角度也说的过去。
因为,《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。
同时,大多数用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集扩展至方法区,或者说使用永久代来实现方法区。
虽然可以牵强的解释这种将方法区和永久带等同对待观点。但最终方法区和永久带还是不同的。一个是标准一个是实现。这就相当于你将java中的接口和接口的实现等同对待了一样。
同时,这种牵强的解释也仅仅是在HotSpot虚拟机上才能勉强成立。其他的虚拟机实现并没有永久带这一说法。
有人说,HotSpot之所以用永久带来实现方法区是因为这样可以不必专门为方法区编写一套内存管理的代码。
大小调节
在1.7之前,可以使用如下参数来调节方法区的大小
- -XX:PermSize
- 方法区初始大小
- -XX:MaxPermSize
- 方法区最大大小
- 超过这个值将会抛出
OutOfMemoryError
异常:java.lang.OutOfMemoryError: PermGen
4 jdk8中的方法区
在jdk8中已经将永久带移除了。也就是说-XX:PermSize
这些参数在jdk8中将是无效的。
移除了,肯定有人来代替他。就是新出现的元空间(Metaspace)来代替原来的永久带。
上文也提到了,方法区中主要存放的是一些描述性信息,即元数据。元空间这个名字起得还是挺形象的,至少比原来的永久带要更加见名之意了。
《Java虚拟机规范(JavaSE7)》中也说了方法区是堆的逻辑组成部分
。
实际上JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap
或者是 Native Heap
。但永久代仍存在于JDK1.7中,但是并没完全移除。
大小调节
在1.8中,可以使用如下参数来调节方法区的大小
- -XX:MetaspaceSize
- 元空间初始大小
- -XX:MaxMetaspaceSize
- 元空间最大大小
- 超过这个值将会抛出
OutOfMemoryError
异常:java.lang.OutOfMemoryError: Metadata space - 在jdk1.7中抛出的异常是这样:java.lang.OutOfMemoryError: PermGen
参考文章
- 《深入理解JVM》
- 《Java虚拟机规范(JavaSE7)》
- 《Java虚拟机规范(JavaSE8)》