Java 方法区永久代元空间

本篇主要讲解方法区/永久代/元空间这三个概念。

Java内存模型回顾

这是个经典的问题,Java的内存模型是什么样的?

堆是所有线程共享的,主要用来存储对象。其中,堆可分为:年轻代老年代两块区域。使用NewRatio参数来设定比例。对于年轻代,一个Eden区和两个Suvivor区,使用参数SuvivorRatio来设定大小

线程私有的,主要存放局部变量表操作数栈动态链接方法出口

程序计数器

同样是线程私有的,记录当前线程的行号指示器,为线程的切换提供保障

方法区

线程共享的,主要存储类信息常量池静态变量JIT编译后的代码等数据。方法区理论上来说是堆的逻辑组成部分

永久代和方法区的关系

涉及到内存模型时,往往会提到永久代,那么它和方法区又是什么关系呢?《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。 同时,大多数用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集扩展至方法区,或者说使用永久代来实现方法区

因此,我们得到了结论,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现。其他的虚拟机实现并没有永久带这一说法。

在1.7之前,可以使用如下参数来调节方法区的大小:

1
2
3
4
5
-XX:PermSize
方法区初始大小
-XX:MaxPermSize
方法区最大大小
超过这个值将会抛出OutOfMemoryError异常:java.lang.OutOfMemoryError: PermGen

元空间

对于Java8, HotSpots取消了永久代,那么是不是也就没有方法区了呢?当然不是,方法区是一个规范,规范没变,它就一直在。那么,取代永久代的就是元空间。它可永久代有什么不同的?

  1. 存储位置不同,永久代物理是是堆的一部分,和新生代,老年代地址是连续的,而元空间属于本地内存。

  2. 存储内容不同,元空间存储类的元信息,静态变量和常量池等并入堆中。相当于永久代的数据被分到了堆和元空间中。