[JVM]二 运行时数据区 (5) 方法区 + 直接内存

文章目录

  • 方法区
    • 方法区的理解
    • 方法区内部结构
    • 栈,堆,方法区的交互关系
    • 方法区大小与OOM
    • 方法区的垃圾回收
  • 直接内存

方法区

方法区的理解

方法区是线程共享的内存区域

方法区大小决定了内存可以保存多少个类,如果定义了太多类导致溢出会发生OOM

JDK7称永久代 JDK8称元空间
区别在于:原空间不在虚拟机设置的内存中,而是使用本地内存

替换原因:为永久代设置空间大小是很难确定的,调优也很困难

方法区内部结构

[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第1张图片
存储被虚拟机加载的类型信息,常量,静态变量,即时编译器编译后的代码缓存

类型信息:堆每个加载的类型(类calss,接口interface,枚举enum,注解annotation),jvm都会在方法区中存储一下类型信息
1)完全限定名
2)直接父类的完全限定名
3)类型的修饰符以及生命顺序(public,abstract,final的某个子集)
4)这个类型直接接口的一个有序列表
5)方法信息(方法名,方法返回类型,方法参数个数和类型,方法修饰符,方法的zi’jie’ma)

[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第2张图片

常量池和运行时常量池

常量池表:包括各种字面量和堆类型,域,方法的符号引用,JVM根据指令找到要执行的各个信息

一个java源文件中的类,接口,编译后产生一个字节码文件,而java中字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里,另一种方式就是存到常量池,这些字节码包含了指向常量池的引用,在动态链接的时候会用到运行时常量池。
[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第3张图片
每个#都是引用存在常量池中基本信息,可以达到复用

运行时常量池:
在加载类和接口到虚拟机时,就会创建对应的运行时常量池
引用转换位真实地址,相对于class文件常量池另一特征是具备动态性。

栈,堆,方法区的交互关系

[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第4张图片
[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第5张图片

方法区大小与OOM

JDK7及之前 使用-XX:PermSize可以设置永久代初始分配空间 默认20.75MB
-XX:MaxPermSize设置最大可分配空间 32位机器默认64MB 64位默认82MB

JDK8之后使用-XX:MetaspaceSize 默认21MB 和-xx:MaxMetaspaceSize 默认-1 即没有限制 参数

21MB是元空间大小的初始高水位线,达到这个大小Full GC会触发自动清理没有用的类,然后将高水位线重置

如何解决OOM:
分清是出现内存泄漏还是内存溢出
1)内存泄漏,找到GC Roots的引用链,找到无法垃圾回收的关联对象的类型性信息
2)如果空间不足发生溢出,减少程序运行期的内存消耗

方法区的垃圾回收

java虚拟机规范中对于方法区的垃圾回收约束是非常宽松的
一般主要分为

常量池中废弃的常量:
只要常量池中的常量没有被任何地方引用,就可以被回收,与回收java堆中的对象类似

不再使用的类型:
需要同时满足:
1)该类所有的实例都已经被回收,包括该类派生的任何子类
2)加载该类的类加载器已经被回收
3)该类对应的java.lang.Class对象没有在任何地方被引用,无法通过反射访问该类的方法。

直接内存

JDK8 引入元空间 而元空间即使用的是 直接内存

直接内存是java堆外,直接向系统申请的内存区域,访问速度优于java堆,读写性能高,用于数据缓冲区

由于直接内存在java堆外,因此他的大小不会受jvm参数指定 ,但以然受限于操作系统能给出的最大内存

缺点:
分配回收成本高
不受JVM内存回收管理

[JVM]二 运行时数据区 (5) 方法区 + 直接内存_第6张图片

你可能感兴趣的:(JVM)