目前有三大Java虚拟机:HotSpot,oracle JRockit,IBM J9。

JRockit是oracle发明的,用于其WebLogic服务器,IBM JVM是IBM发明的用于其Websphere服务器(因此在某行开发的时候,他们用的是IBM的JDK,由于他们使用的IBM的应用程序服务器Websphere,使用其余JDK可能存在兼容性问题)。spring

JRockit和J9不存在永久代这种说法。这里只讨论HotSpot虚拟机,这也是目前使用的最多的JVM。Sun JDK7 HotSpot虚拟机的内存模型以下图所示:服务器

一、什么是方法区

在Java虚拟机中,方法区是可供各线程共享的运行时内存区域。并发

在不一样的JDK版本中,方法区中存储的数据是不同的。oracle

在JDK1.6及以前,运行时常量池是方法区的一个部分,同时方法区里面存储了类的元数据信息、静态变量、即时编译器编译后的代码(好比spring 使用IOC或者AOP建立bean时,或者使用cglib,反射的形式动态生成class信息等)等。性能

在JDK1.7及之后,JVM已经将运行时常量池从方法区中移了出来,在JVM堆开辟了一块区域存放常量池。优化

二、方法区和永久代的关系

在Java虚拟机规范中,方法区在虚拟机启动的时候建立,虽然方法区是堆的逻辑组成部分,可是为了与堆进行区分,一般又叫“非堆”。可是简单的虚拟机实现能够选择不在方法区实现垃圾回收与压缩。这个版本的虚拟机规范也不限定实现方法区的内存位置和编译代码的管理策略。因此不一样的JVM厂商,针对本身的JVM可能有不一样的方法区实现方式。线程

在HotSpot中,设计者将方法区归入GC分代收集。HotSpot虚拟机堆内存被分为新生代和老年代,对堆内存进行分代管理,因此HotSpot虚拟机使用者更愿意将方法区称为老年代。设计

方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。接口

咱们知道在HotSpot虚拟机中存在三种垃圾回收现象,minor GC、major GC和full GC。对新生代进行垃圾回收叫作minor GC,对老年代进行垃圾回收叫作major GC,同时对新生代、老年代和永久代进行垃圾回收叫作full GC。许多major GC是由minor GC触发的,因此很难将这两种垃圾回收区分开。major GC和full GC一般是等价的,收集整个GC堆。但由于HotSpot VM发展了这么多年,外界对各类名词的解读已经彻底混乱了,当有人说“major GC”的时候必定要问清楚他想要指的是上面的full GC仍是major GC。内存

三、元空间

上面说过,HotSpot虚拟机在1.8(包括)以后已经取消了永久代,改成元空间,类的元信息被存储在元空间中,而常量池依旧存在于堆内存中。元空间没有使用堆内存,而是与堆不相连的本地内存区域。因此,理论上系统可使用的内存有多大,元空间就有多大,因此不会出现永久代存在时的内存溢出问题。这项改造也是有必要的,永久代的调优是很困难的,虽然能够设置永久代的大小,可是很难肯定一个合适的大小,由于其中的影响因素不少,好比类数量的多少、常量数量的多少等。永久代中的元数据的位置也会随着一次full GC发生移动,比较消耗虚拟机性能。同时,HotSpot虚拟机的每种类型的垃圾回收器都须要特殊处理永久代中的元数据。将元数据从永久代剥离出来,不只实现了对元空间的无缝管理,还能够简化Full GC以及对之后的并发隔离类元数据等方面进行优化。

四、元空间取代永久代的好处:

一、字符串存在永久代中,容易出现性能问题和内存溢出。

二、类及方法的信息等比较难肯定其大小,所以对于永久代的大小指定比较困难,过小容易出现永久代溢出,太大则容易致使老年代溢出。

三、永久代会为 GC 带来没必要要的复杂度,而且回收效率偏低。

四、Oracle 可能会将HotSpot 与 JRockit 合二为一。