JVM运行时数据区-方法区
- 方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、域信息、方法信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。很多人都更愿意把方法区称为“永久代”(Permanent Generation)。从jdk1.7已经开始准备“去永久代”的规划,jdk1.7的HotSpot中,已经把原本放在方法区中的静态变量、字符串常量池等移到堆内存中。
- 在JDK1.8中,永久代已经不存在,存储类型信息、域信息、方法信息、运行时常量池都已经从永久代搬迁到了元空间。但元空间并不在Java虚拟机之中,而是使用本地内存。所以在默认情况下,元空间的大小仅受到本地内存限制,不过可以通过以下参数来指定元空间大小:
- -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize指定 默认值依赖于平台。windows下,-XX:MetaspaceSize是21M,-XX:MaxMetaspaceSize的值是-1,即没有限制。
- 方法区同堆一样,也是线程共享的内存区域。
- 方法区与堆一样随JVM虚拟机启动被创建,以处于物理上不连续的内存空间,只需逻辑上连续即可。
- 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutofMemoryError:PermGen space 或者java.lang.OutOfMemoryError:Metaspace
- 加载大量的第三方的jar包
- Tomcat部署的工程过多(30~50个)
- 大量动态的生成反射类
- 关闭JVM就会释放这个区域的内存。
- 方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。
- 当俩个线程需要加载一个类型时,只会有一个请求
classloader
,另一个等待。 - 局部变量表的大小以及异常表在方法区中。