方法区
1.基本概念
方 法 区 , 是 一 个 被 线 程 共 享 的 内 存 区 域 。 其 中 主 要 存 储 加 载 的 类 字 节 码 、class/method/field 等元数据、static final 常量、static 变量、即时编译器编译后的代码等数据。另外,方法区包含了一个特殊的域“运行时常量池”。
Java 虚拟机规范中明确说明:”尽管所有的方法区在逻辑上是属于堆的一部分,但对于HotSpotJVM 而言,方法区还有一个别名叫做 Non-Heap(非堆),目的就是要和堆分开. 所以,方法区看做是一块独立于 java 堆的内存空间.
- 方法区在 JVM 启动时被创建,并且它的实际的物理内存空间中和 Java 堆区一样都可以是不连续的.
- 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展.
- 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出, 虚拟机同样会抛出内存溢出的错误:java.lang.OutOfMemoryError:Metaspace
2.方法区,栈,堆的交互关系
3.方法区大小设置
java 方法区的大小不必是固定的,JVM 可以根据应用的需要动态调整.
-
元 数 据 区 大 小 可 以 使 用 参 数 -XX:MetaspaceSize 和-XX:MaxMataspaceSize 指定,替代上述原有的两个参数.
-
默认值依赖于平台,windows 下,-XXMetaspaceSize 是 21MB,
-
-XX:MaxMetaspaceSize 的值是-1,级没有限制.
-
这个-XX:MetaspaceSize 初始值是 21M 也称为高水位线 一旦触及 就会触发 Full GC. 因此为了减少 FullGC 那么这个-XX:MetaspaceSize 可以设置一个较高的值
4.方法区的内部结构
方法区它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存,运行常量池等。
通过反编译字节码文件查看.
反编译字节码文件,并输出值文本文件中,便于查看。参数 -p 确保能查看private 权限类型的字段或方法
javap -v -p 类名.class > test.txt
5.方法区的垃圾回收
-
有些人认为方法区(如 Hotspot 虚拟机中的元空间或者永久代)是没有垃圾收集行为的,其实不然。《Java 虚拟机规范》对方法区的约束是非常宽松的,提到过可以不要求虚拟机在方法区中实现垃圾收集。
-
一般来说这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻。但是这部分区域的回收有时又确实是必要的。
-
方法区的垃圾收集主要回收两部分内容:运行时常量池中废弃的常量和不再使用
的类型。 -
收废弃常量与回收 Java 堆中的对象非常类似。
类卸载
判定一个类型是否属于“不再被使用的类”
- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类及其任何派生子类的实例。
- 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如 OSGi、JSP 的重加载等,否则通常是很难达成的。
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
va.lang.Class 对象没有在任何地方被引用**,无法在任何地方通过反射访问该类的方法。