一. 方法区概述
用于存储类的结构信息、常量、静态变量、即时编译器优化后的代码等数据的内存区域。方法区通过元空间实现。对于GC而言,较多的收集新生代,较少的收集老年代,几乎不动元空间。
线程共享的区域。在虚拟机启动时被创建,是堆空间的逻辑上的一部分。该内存在物理上不连续,在逻辑上连续。方法区的大小可以固定或可扩展,该大小决定了系统可以保存多少个类。
JDK7以前,习惯上把方法区称作永久代;JDK8以后,元空间取代了永久代。元空间相比永久代,不设置在虚拟机内存中,而使用本地内存。从而避免了永久代容易OOM的缺点。避免了永久代空间难以设置、调优困难的缺陷(方法区的GC主要回收不使用的常量和废弃的类。类的卸载是比较困难的)。
二. 方法区参数
-XX:MetaspceSize 设置元空间初始分配空间。如果设置的太低,会导致该空间容易满,从而频繁full gc。
-XX:MataspcaeMaxSize:设置元空间最大可分配空间。
三. 方法区的内部结构
- 类型信息
- 域信息(成员变量/类变量)
static final在编译阶段完成赋值; static在prepare阶段完成内存空间分配,在初始化阶段完成赋值。 - 方法信息
(方法信息在调用方法时才会入栈出栈)
- 运行时常量池
常量池用于存放编译期生成的各种字面量和符合引用。 字节码文件中的常量池通过类加载,成为方法区中的运行时常量池。加载后,符合引用变成真实地址。运行池常量池具备动态性(常量池,只能放代码中存在的信息,在编译期间,就确定了,不会再得到更改;运行时常量池,则可以通过代码动态的往里面塞信息。)
四. jdk1.6、1.7、1.8的变换
(注意,这里说的静态变量是指的变量(引用)而不是实例)
永久代垃圾回收效率低,full gc才会触发永久代垃圾回收。导致String回收效率低,从而将串池调整到了堆中。
五. 方法区的垃圾回收
六. 直接内存
直接内存的大小受限于系统内存的大小,所以也会产生OOM的异常。