【培训】DAY13(中)方法区

版权声明:本文内容来源于网络,如有侵权请联系删除 https://blog.csdn.net/ZyhMemory/article/details/88895666

定义

方法区也是所有线程共享。主要用于存储类的信息、常量池、方法数据、方法代码等。
方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。

特点

  1. 方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。
    例如,假如同时有两个线程都企图访问方法区中的同一个类,而这个类还没有被装入JVM,那么只允许一个线程去装载它,而其它线程必须等待
  2. 方法区的大小不必是固定的,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配。
  3. 方法区也可被垃圾收集,当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集

存储的类信息

对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:

  1. 这个类型的完整有效名称(全名=包名.类名)
  2. 这个类型直接父类的完整有效名称( java.lang.Object除外,其他类型若没有声明父类,默认父类是Object
  3. 这个类型的修饰符(public、abstract、final的某个子集)
  4. 这个类型直接接口的一个有序列表

存储的静态变量

  1. 静态变量又称为类变量,类中被static修饰的成员变量都是静态变量(类变量),静态变量之所以又称为类变量,是因为静态变量和类关联在一起,随着类的加载而存在于方法区(而不是堆中)
  2. 八种基本数据类型(byte、short、int、long、float、double、char、boolean)的静态变量会在方法区开辟空间,并将对应的值存储在方法方法区,对于引用类型的静态变量如果未用new关键字为引用类型的静态变量分配对象(如:static Object obj;)那么对象的引用obj会存储在方法区中,并为其指定默认值null;
    若对于引用类型的静态变量如果用new关键字为引用类型的静态变量分配对象(如:static Person person = new Person();),那么对象的引用person 会存储在方法区中,并且该对象在堆中的地址也会存储在方法区中(注意此时静态变量只存储了对象的堆地址,而对象本身仍在堆内存中)

存储的方法

jvm必须保存所有方法的以下信息

  1. 方法名
  2. 方法的返回类型(或 void)
  3. 方法参数的数量和类型(有序的)
  4. 异常表
  5. 方法的修饰符(public, private, protected, static, final, synchronized, native, abstract的一个子集)
    除了abstract和native方法外,其他方法还有保存方法的字节码(bytecodes)操作数栈和方法栈帧的局部变量区的大小

永久代

在Java虚拟机规范中,方法区在虚拟机启动的时候创建,虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择不在方法区实现垃圾回收与压缩。这个版本的虚拟机规范也不限定实现方法区的内存位置和编译代码的管理策略。所以不同的JVM厂商,针对自己的JVM可能有不同的方法区实现方式。
在HotSpot中,设计者将方法区纳入GC分代收集。HotSpot虚拟机堆内存被分为新生代和老年代,对堆内存进行分代管理,所以HotSpot虚拟机使用者更愿意将方法区称为永久代。
方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。
需要注意的是Java1.8之后就取消了永久代

元空间

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

猜你喜欢

转载自blog.csdn.net/ZyhMemory/article/details/88895666