什么是方法区?
前面了解了JVM内存结构中的程序计数器、虚拟机栈、本地方法栈和堆之后,还有最后一个内存结构——方法区。
方法区从名字上看与我们类的方法有关,确实如此,但是还不是很完整的概括,对于方法区的定义各有千秋,但在JVM规范中是这样定义的。

从其定义,首先可以得到,方法区是所有线程共享的区域。其次,在方法区中存放了跟类结构的相关信息(运行时常量池),包括成员变量、方法数据,成员方法以及构造方法的代码部分。
方法区在虚拟机启动的时候创建,它在逻辑上是堆的一个组成部分。方法区只是一个概念,并不是一个具体的实现,对于方法区具体内容如下图:

在JDK1.6中,方法区的实现使用了一个永久代实现,在永久代中可以存储类的信息、类加载器还有一块就是运行时常量池,在常量池有一个非常重要的一个串池——StringTable。在1.8中方法区用永久代的实现方式被废弃,改为由一个元空间的来实现,同样在元空间包含了类信息、类加载器、常量池,这个时候方法区已经不占用堆内存,换句话说此时方法区就不是由JVM来管理它的内存结构,它已经移出到本地内存中,所谓本地内存就是操作系统的内存,在1.8中StringTable已经不是在方法区,而是在堆中。
方法区的内存溢出问题
方法区就是来存储类的结构数据,当类加载过多时,就会出现OutOfMemoryError的,即内存溢出。在1.8版本因为元空间是直接使用的操作系统内存,而操作系统的内存现在一般是4G、8G、16G,所以出现内存溢出是很少的,但是如果设置虚拟机的参数:-XX:MaxMetaspacesize+大小,就可以模拟出内存溢出的问题。在1.8以前也是受永久代的空间大小会出现内存溢出的问题,同样可以通过设置虚拟机参数:-XX:MaxPermSize+大小也可以模拟出内存溢出的问题。

通过类加载模拟元空间内存溢出
如今,我们常用的框架Spring、Mybatis这些框架都会大量的在运行时生成类,在1.8之前很容易导致永久代空间不足,在1.8之后由于元空间使用的是系统内存,相对而言充裕了很多,并且垃圾回收机制也是由元空间自行管理,不会像永久代垃圾回收效率比较低。
















