**黄色区域:**所有线程共享的内存区域,会存在垃圾回收。
**灰色区域:**线程私有不会产生垃圾回收。
方法区是运行时数据区中的一部分,那么方法区具体的用途是什么呢?方法区能存放什么信息呢?
方法区和堆一样是被所有的线程所共享,有的地方将方法区称之为Non-Heap(非堆),其目的就是将方法区与堆内存区分开来,在JDK1.7中很多开发者将方法区称之为永久代,但本质上两者并不是等价的,仅仅是因为HotSpot虚拟机的设计团队将GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已,这样HotSpot的垃圾收集器可以像管理堆内存一样管理永久代内存了,其余非HotSpot的虚拟机是没有永久代这个概念的。
方法区在jdk7及以前,习惯将永久代称之为方法区,结构如下所示
在jdk1.8中采用了Metaspace(元数据空间)替换了Perm(永久区),并且从堆空间分离出来,结构如下所示
一定一定需要注意的是Metaspace(元数据空间)不再存储到堆中,也不使用JVM内存空间而是采用本机的内存,这样元数据只受本地内存大小限制,OOM的问题就不存在了。
为什么JDK1.8需要将方法区从JVM永久代(非直接内存)移到元空间(直接内存)呢?
JVM永久代存在容量限制,那么类信息存储的容量有限制容易触发OOM,而采用元空间存储,只受本地内存大小限制OOM的可能性小。
因为是直接内存,JVM将会在IO操作上具有更高的性能,因为它直接作用于本地操作系统的IO操作,而堆内存做IO操作,先需要将数据复制到直接内存,再利用IO处理,而直接内存不需要这层转换。
如我们常常构建的业务对象,以Car对象为例
当我们在代码中创建一个Car实例对象后,将会在堆、栈、方法区内存空间分别写入数据
Car:是对象模板,为Class对象,存放在方法区中。
car:属于引用数据,存放栈空间中。
new Car():需要在堆中开辟一片空间,存放在堆中。
方法区存放的数据主要是被类加载器加载后的类信息,运行时常量池等等。
其中有两个点需要注意
静态变量,在JDK1.8以前静态变量都是存在永久代内存中,JDK1.8后采用元空间替代永久代,==就将静态变量从永久代转移到了堆空间==。
常量池,在JDK1.7之前运行时常量池逻辑包含了字符串常量池存放在永久代中,JDK1.7将字符串常量池转移到了堆内存中,注意这时并没有提到运行时常量池,也就是说运行时常量池还存在永久代中,JDK1.8将永久代移除用元空间代替,这时运行时常量池就存在元空间中了。
那么类信息又包括什么东西呢?
类信息
类的完整名字
类的直接父类完整名字
类的直接实现接口有序列表
类型标识(是类还是接口)
类的访问修饰符(public、private等等)
类型常量池
存放该类型用到的常量有序集合,包括直接常量(字符串、浮点、整型),和对其它类型、字段、方法的符号引用。
字段信息
字段类型、名称、访问修饰符等
方法信息
类的所有方法
方法返回类型、方法访问修饰符、方法名称等等
类变量
指向类加载器的引用
指向Class实例的引用
方法表