JVM运行时数据区-方法区

  • 方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、域信息、方法信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。很多人都更愿意把方法区称为“永久代”(Permanent Generation)。从jdk1.7已经开始准备“去永久代”的规划,jdk1.7的HotSpot中,已经把原本放在方法区中的静态变量、字符串常量池等移到堆内存中。

    image-20200708211541300

    image-20200708211609911

    img

    • 方法区主要存放Class,堆主要存放实例化的对象。
  • 在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就会释放这个区域的内存。

  • 方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

程序计数器

虚拟机栈

本地方法栈

Java堆

Q.E.D.


一个热爱生活的95后精神小伙