方法区的基本概念

  • 方法区和堆一样是多个线程共享的,

  • 《java虚拟机规范》中声明,所有的方法区在逻辑上可以看作是堆的一部分,但是一些简单的实现可能不会选择区进行垃圾收集或者压缩,

  • 而对于hotSpot而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开,所以,方法区可以看作是一块独立与堆的内存空间,而且堆的主要目的是存放创建出来的各种对象,方法区里则会有类的信息,从内容来说,也不相同

  • 方法区在jvm启动时被创建,它的实际物理内存空间和java堆区一样都是可以不连续的

  • 方法区的大小和堆空间一样,可以固定大小也可以扩展

  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法去溢出,虚拟机同样会抛出oom:PermGen space 或者oom : Metspace (1.7之前叫做永久代,1.8叫元空间,报的错误也不一样)

  • 关闭jvm就会释放这个区域的内存

1.7之前习惯性的把方法区叫做永久代,1.8使用元空间取代了永久代,(可以把方法区看作是接口,永久代和元空间都是对应的实现)

  • 方法区和永久代并不等价,只是在hotSpot中是等价的,《java虚拟机规范》中并没有规定具体的实现,不同的虚拟机是不一样的,

  • 永久代使用的是虚拟机的内存,内存方面限制较大,容易溢出

  • 元空间采用的是本地内存来实现的,空间更大

设置方法区的大小

  • jdk1.7的永久代

    -XX:PermSize 初始分配空间 ,默认:20.75M

    -XX:MaxPermSize 最大空间 ,32位物理机默认64M,64位默认82M

  • 1.8 元空间:因为用的是本地内存,所以和平台有关系

    -XX:MetaspaceSize 初始分配空间 ,windows默认21M

    -XX:MaxMetaspaceSize 最大空间 ,默认是-1,也就是没有限制

    • 对于初始的元空间大小,会被认为是高水位线,一旦触及这个水位线,就会执行Full GC,卸载没用的类,然后重置高水位线,新的高水位线的取值取决于GC回收了多少元空间,如果释放的空间不足,在不超过最大空间时,会适当提高水位线,如果释放空间过多,会降低水位线
    • 所以如果初始化水位线设置过低,高水位线会频繁变动,所以建议初始水位线设置一个较高的值

方法区的内部结构

文件被加载到方法区后,会保留是被哪一个类加载器加载的该文件,也算是类的一部分

方法区用于存储已被虚拟机加载的类型信息(类、接口、枚举、注解)、常量、静态变量、即时编译器编译后的代码缓存等

  • 类型信息:对每个加载的类型信息,jvm必须在方法区中存储以下类型信息:

    • 这个类型完整有效名称(全名=包名.类名)
    • 这个类型直接父类的完整有效名(接口或者object是没有父类的)
    • 这个类型的修饰符(public、abstract、final)
    • 这个类型直接接口的一个有序列表(可能会实现了多个接口,是一个有序的列表)
  • 域(Feild,俗称属性)信息

    • jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序
    • 域的相关信息包括:域名称、域类型、域修饰符
  • 方法信息:

    • 方法名称
    • 方法返回类型
    • 方法参数的数量、类型(是有序的)
    • 方法修饰符
    • 方法字节码、操作数栈、局部变量表及其大小
    • 异常表(异常开始位置、结束位置等)

non-final的类变量

  • 静态变量和类关联在一起,随着类的加载而加载,成为类数据在逻辑上的一部分
  • 类变量被所有实例共享

全局常量(final 的 static),在编译的时候就会被分配了

运行时常量池

方法区内部包含了运行时常量池。

字节码文件,包含常量池,把常量池的信息加载到内存后,就叫做运行时常量池

常量池包含了各种字面量和对类型、域和方法的符号引用,也就是一些基本信息

常量池可以看作是一张表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等信息

  • 常量池是字节码文件的一部分,用于存放编译时生成的各种字面量与符号引用,这部分内容在类加载后会存放到方法区的运行时常量池

  • 运行时常量池是方法区的一部分

  • 每个类或接口都会有一个常量池,当中的数据就像数组一样,可以用索引来访问

  • 运行时常量池中,存储的就不是符号引用了,是真实的地址

  • 运行时常量池相较于常量池来说,具备动态性,有可能常量池中并没有相关信息,比如虚方法等


而字符串常量池再1.6的时候是在永久代的,而1.7就转移到了堆中,1.8虽然去除了永久代,改为元空间,但是字符串常量池依然保留在了堆中,而不是方法区

方法区的演变

只有hotspot才有永久代

在jdk1.6之前,有永久代,而且静态变量存放在永久代上(new的对象的实体始终在堆中,引用在永久代)

1.7,依然有永久代,但是已经在逐步去除永久代了,字符串常量池、静态变量等从永久代中移除,转移到堆中

1.8及以后,就没有永久代了,类型信息、字段、方法、常量保存至本地内存的元空间,但是字符串常量池、静态变量依然放在堆中

为什么要用元空间代替永久代

官方给的消息是,jdk8 ,oracle将hotSport 和 JRockit 进行了整合,而 JRockit 是没有永久代的,所以1.8也没有永久代

也有以下原因:

  • 永久代的空间大小难以确定,如果动态加载的类太多,会频繁出现错误,而元空间采用的是本地内存,不受虚拟机内存的限制
  • 对永久代的调优很难,想要回收类,条件很苛刻(full GC 代价很大)

字符串常量池的变化

jdk 7 将StringTable放到了堆空间,因为永久代的回收效率很低,只有在full gc 是才会触发,而full GC 是老年代、永久代不足时才会触发,这就使得StingTable回收效率不高,而一般开发中通常会有大量的字符串被创建,如果回收效率低,容易导致永久代内存不足,放在堆里。可以及时的回收内存

方法区的垃圾回收

《java虚拟机规范》对方法区的约束是比较宽松的,方法区的垃圾回收,在不同的虚拟机实现是不同的,是可以不进行垃圾回收的

一般来说,方法区的垃圾回收效果是比较困难的,尤其是类型的卸载,条件十分苛刻,但是方法区的回收有时又是非常由必要的,否则有可能会出现内存泄漏

方法区的垃圾回收主要涉及两部分:

  • 常量池中废弃的常量:字面量和符号引用

    • 字面量:文本字符串、final的常量值 (比较接近java语言层次)
    • 符号引用:类、接口的全限定名,字段的名称和描述符,方法的名称和描述符 (属于编译原理的概念)
    • 对于常量池的回收策略很明确:只要常量池中的常量没有被任何地方引用,就可以回收
  • 不在使用的类型:想要判定类型是否是不在被使用的条件是很苛刻的,需要满足以下全部条件
    • 所有的实例都被回收了,且不存在任何子类实例
    • 加载该类的类加载器已经被回收了
    • 该类的 .class 对象没有被任何地方引用
    • 只有全部满足上面的三个条件,才允许被回收,而不是一定会回收

java虚拟机方法区相关推荐

  1. java 虚拟机_浅谈Java虚拟机内存区

    1. Java 虚拟机内存区概述 我们在编写程序时,经常会遇到OOM(out of Memory)以及内存泄漏等问题.为了避免出现这些问题,我们首先必须对JVM的内存划分有个具体的认识.JVM将内存主 ...

  2. 2021-02-23关于java的方法区,为什么叫方法区,是否与实际用途相悖?

    关于java的方法区,为什么叫方法区,是否与实际用途相悖? 在java中,栈中存放的是用来保存方法运行时状态的栈帧,存储了局部变量表,操作数栈等,而方法区存放的是已加载的类的基本信息.常量.静态变量等 ...

  3. java堆栈方法区_java 栈 ,堆, 方法区

    栈的特点如下: 1. 栈描述的是方法执行的内存模型.每个方法被调用都会创建一个栈帧(存储局部变量.操作数.方法出口等) 2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数.局部变 ...

  4. java虚拟机及加载class文件的原理机制

    2019独角兽企业重金招聘Python工程师标准>>> (点击获取更多资料的下载) java 虚拟机 ‎2007‎年‎4‎月‎23‎日,‏‎14:18:00 | chenweicai ...

  5. Java虚拟机 和 java虚拟机下的进程

    一.什么是Java虚拟机      当你谈到Java虚拟机时,你可能是指:      1.抽象的Java虚拟机规范      2.一个具体的Java虚拟机实现      3.一个运行的Java虚拟机实 ...

  6. Java虚拟机(九)——方法区

    文章目录 堆.栈.方法区的交互关系 线程是否共享: 三者的交互关系: 方法区的理解 方法区的位置 基本理解: 设置方法区大小 JDK7以前 JDK8及以后: 方法区的内部结构 方法区存储什么 类型信息 ...

  7. JVM-内存区域 堆、方法区,虚拟机栈、程序计数器详解

      JVM 把内存分为若干个不同的区域,这些区域有些是线程私有的,有些则是线程共享的,Java 内存区域也叫做运行时数据区,它的具体划分如下: 虚拟机栈   Java 虚拟机栈是线程私有的数据区,Ja ...

  8. 【JAVA】堆、栈与方法区

    一.Java中的内存管理: 1.程序,无论是代码还是数据,都需要存储在内存中,JVM为Java程序提供并管理所需要的内存空间. 2.JVM内存分为堆(heap).栈(stock).方法区(method ...

  9. 玩点深入的:Java 虚拟机内存结构及编码实战

    本文来源:不会coding 了解JVM内存结构的目的 在Java的开发过程中,因为有JVM自动内存管理机制,不再需要像在C.C++开发那样手动释放对象的内存空间,不容易出现内存泄漏和内存溢出的问题. ...

最新文章

  1. 赢得高薪的锦囊三秘诀
  2. 牛批了,1行python代码就可实现炫酷可视化
  3. python列表的实现原理_Python列表对象实现原理
  4. @RequestBody, @ResponseBody 注解详解
  5. 阿里云1C2G虚拟机【99/年】羊毛党集合啦!
  6. mybatis_user_guide(5) 动态 SQL
  7. 95-10-040-启动-限额管理
  8. 在SQL SERVER里面用命令查包含某字段的表
  9. 分享一些不错的sql语句
  10. ReactJS基础(续)
  11. OpenGL ES 中的模板测试
  12. java菜鸟突破面试系列-终章
  13. 通达OA2017 工作流设计中“退回”功能的升级测试(图文)
  14. Visio绘图工具,“连接线”命令使用方法
  15. 有赞订单搜索AKF架构演进之路
  16. 2014腾讯实习生招聘数组墙算法
  17. windows10下安装choco
  18. 2015年京胜杯删数!删数
  19. 台式计算机碟片怎么安装,怎样用光盘从装台式电脑系统?
  20. Apache Solr 任意文件读取

热门文章

  1. MyBatis动态sql语句使用
  2. jq实现ajax文件上传
  3. MySQL 数据库渗透及漏洞利用总结
  4. 金三银四跳槽季,这份宝典让你一路开挂
  5. 传字节跳动将进军云计算IaaS,“狼来了”?
  6. 荣耀九x升级鸿蒙,不会区别对待!荣耀老机型升级鸿蒙OS名单出炉!荣耀9X得到确认!...
  7. 10月14日苹果第二场秋季新品发布会 iphone12发布时间确定
  8. 基于selenium实现UI自动化
  9. Python单元测试及unittest框架用法实例解析
  10. Swagger UI 配置