方法区和永久代

1.方法区和永久代的关系

  涉及到内存模型时,往往会提到永久代,那么它和方法区又是什么关系呢?《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。 同时大多数用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集扩展至方法区,或者说使用永久代来实现方法区。因此,我们得到了结论,永久代是HotSpot的概念,方法区是Java虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现。其他的虚拟机实现并没有永久带这一说法。在1.7之前在(JDK1.2 ~ JDK6)的实现中,HotSpot 使用永久代实现方法区,HotSpot 使用 GC分代来实现方法区内存回收,可以使用如下参数来调节方法区的大小:

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

JDK1.8之前调节方法区大小:

  -XX:PermSize=N //方法区(永久代)初始大小

  -XX:MaxPermSize=N //方法区(永久代)最大大小,超出这个值将会抛出OutOfMemoryError 

JDK1.8开始方法区(HotSpot的永久代)被彻底删除了,取而代之的是元空间,元空间直接使用的是本机内存。参数设置:

  -XX:MetaspaceSize=N //设置Metaspace的初始(和最小大小)

  -XX:MaxMetaspaceSize=N //设置Metaspace的最大大小

 

2.元空间
      对于Java8, HotSpots取消了永久代,那么是不是也就没有方法区了呢?当然不是,方法区是一个规范,规范没变,它就一直在。那么取代永久代的就是元空间。它可永久代有什么不同的?存储位置不同,永久代物理是是堆的一部分,和新生代,老年代地址是连续的,而元空间属于本地内存;存储内容不同,元空间只存储类和类加载器的元数据信息,静态变量和常量池等并入堆中。相当于永久代的数据被分到了堆和元空间中。

3.永久代和元空间内存使用上的差异:

  Java虚拟机规范中只定义了方法区用于存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据

    1)jdk1.7开始符号引用存储在native heap中,字符串常量和静态类型变量存储在普通的堆区中,但分离的并不彻底,此时永久代中还保存另一些与类的元数据无关的杂项

    2)jdk8后HotSpot 原永久代中存储的类的元数据将存储在metaspace中,而类的静态变量和字符串常量将放在Java堆中,metaspace是方法区的一种实现,只不过它使用的不是虚拟机内的内存,而是本地内存。在元空间中保存的数据比永久代中纯粹很多,就只是类的元数据,这些信息只对编译期或JVM的运行时有用。

    3)永久代有一个JVM本身设置固定大小上线,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,并且永远不会得到java.lang.OutOfMemoryError。
    4) 符号引用没有存在元空间中,而是存在native heap中,这是两个方式和位置,不过都可以算作是本地内存,在虚拟机之外进行划分,没有设置限制参数时只受物理内存大小限制,即只有占满了操作系统可用内存后才OOM。

 
4.关键词分析:
  1)元数据:
    元数据是关于数据的数据。在编程语言上下文中,元数据是添加到程序元素如方法、字段、类和包上的额外信息。对数据进行说明描述的数据
     注解Annotation就是java平台的元数据
      元数据以标签的形式存在于Java代码中。 
      元数据描述的信息是类型安全的,即元数据内部的字段都是有明确类型的。 
      元数据需要编译器之外的工具额外的处理用来生成其它的程序部件。 
       元数据可以只存在于Java源代码级别,也可以存在于编译之后的Class文件内部。
  ·  在注解诞生之前,程序的元数据存在的形式仅限于xml 部署描述文件、java注释或javadoc,
      但注解可以提供更多功能,它不仅包含元数据,还能作用于运行期,注解解析器能够使用注解决定处理流程
  2)符号引用
     符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可。比如org.simple.People类引用了                    org.simple.Language类,在编译时People类并不知道Language类的实际内存地址,因此只能使用符号org.simple.Language(假设是这个,当然实际中是由类似于     CONSTANT_Class_info的常量来表示的)来表示Language类的地址。
      在JVM中类加载过程中,在解析阶段,Java虚拟机会把类的二级制数据中的符号引用替换为直接引用。
  3)直接引用可以是
    1)直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
    2)相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
    3)一个能间接定位到目标的句柄
posted @ 2020-04-02 14:33  whhhd  阅读(3315)  评论(0编辑  收藏  举报