8. 方法区
8.1 方法区的基本理解
- 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
- 方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。
- 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
- 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:
java.lang.outOfMemory PermGen space或者java.lang.outOfMemoryError: Metaspace - 关闭JVM就会释放这个区域的内存。
JDK8放弃永久代的概念,使用JRockit的元空间来代替。元空间不再虚拟机设置的内存中,而是使用本地内存
8.2 方法区的大小的设置与OOM
-
jdk7及以前:
- 通过
-XX:PermSize来设置永久代初始分配空间。默认值是20.75M -
-XX:MaxPernSize来设定永久代最大可分配空间。32位机器默认是64M,64位机器模式是82M - 当JVM加载的类信息容量超过了这个值,会报异常outOfMemoryError:PermGenspace。
- 通过
-
jdk8及以后:
- 元数据区大小可以使用参数
-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定,替代上述原有的两个参数。 - 默认值依赖于平台。windows下,
-XX:MetaspaceSize是21M,-XX:MaxMetaspaceSize的值是-1,即没有限制。 -
-XX:MetaspaceSize设置的是初始的高水位线,触及这个水位线FullGC被触发,根据释放的空间调整高水位线,如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到Full GC多次调用。为了避免频繁地GC,建议将-XX:MetaspaceSize设置为一个相对较高的值。
- 元数据区大小可以使用参数
注意用等号赋值(永久代或者元空间)设置,例如:
-XX:MetaspaceSize=100M
8.3 方法区
- 方法区主要存储虚拟机加载的类型信息、常量、静态变量、及时编译器编译后的代码缓存、类加载器。
类型信息:实现的接口序列、修饰符、直接父类的完整有效名、类的完整有效名等
域(filed属性)信息:修饰符、名称等
方法的信息:名称、返回类型、参数数量和类型、方法的修饰符等
8.4 常量池
字节码:一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含一项信息那就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用。
8.5 运行时常量池
- 运行时常量池(Runtime Constant Poo1)是方法区的一部分。
- 常量池表(Constant Pool Table)是class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
只有HotSpot才有永久代
8.6 方法区的演进
| 版本 | 变化 |
|---|---|
| jdk1.6及以前 | 有永久代,静态变量存放在永久代上 |
| jdk1.7 | 有永久代,但己经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中 |
| jdk1.8及之后 | 无永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆里 |
永久代为什么被替换?
- 为永久代设置空间大小是很难确定的。
- 对永久代进行调优是很困难的
方法区的垃圾回收主要有什么?
- 常量池中废弃的常量
- 不再使用的类型
判断常量不会被使用是很费时间的,这样调优也就比较困难
StringTable为什么要调整?
- jdk7中将stringTable放到了堆空间中。因为永久代的回收效率很低,在full ge的时候才会触发。而full gc是老年代的空间不足、永久代不足时才会触发。这就导致stringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。
8.7 方法区的垃圾收集
-
如何判断一个常量是否被‘废弃’?
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
- 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。
- 该类对应的java.lang.class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
并不是满足上述三个条件就会被回收,而是允许被回收。HotSpot虚拟机提供了
-Xnoclassgc参数进行控制 -
方法区的垃圾主要回收:常量池中废弃的常量和不再使用的类型。