【jvm--方法区】

文章目录

  • 1. 栈、堆、方法区的交互关系
  • 2. 方法区的内部结构
  • 3. 运行时常量池
  • 4. 方法区的演进细节
  • 5. 方法区的垃圾回收

在这里插入图片描述

1. 栈、堆、方法区的交互关系

在这里插入图片描述

方法区的基本理解

  • 方法区(Method Area)与 Java 堆一样,是各个线程共享的内存区域。
  • 方法区在 JVM 启动的时候被创建,并且它的实际的物理内存空间中和 Java 堆区一样都可以是不连续的。
  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutOfMemoryError: PermGen space 或者java.lang.OutOfMemoryError: Metaspace
    • 加载大量的第三方的 jar 包;Tomcat 部署的工程过多(30~50 个);大量动态的生成反射类
  • 关闭 JVM 就会释放这个区域的内存。

元空间不在虚拟机设置的内存中,而是使用本地内存

2. 方法区的内部结构

在这里插入图片描述
在这里插入图片描述

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

  1. 这个类型的完整有效名称(全名=包名.类名)
  2. 这个类型直接父类的完整有效名(对于 interface 或是 java.lang.object,都没有父类)
  3. 这个类型的修饰符(public,abstract,final 的某个子集)
  4. 这个类型直接接口的一个有序列表

域(Field)信息
JVM 必须在方法区中保存类型的所有域的相关信息以及域的声明顺序。

域的相关信息包括:域名称、域类型、域修饰符(public,private,protected,static,final,volatile,transient 的某个子集)

方法(Method)信息

  1. 方法名称
  2. 方法的返回类型(或 void)
  3. 方法参数的数量和类型(按顺序)
  4. 方法的修饰符(public,private,protected,static,final,synchronized,native,abstract 的一个子集)
  5. 方法的字节码(bytecodes)、操作数栈大小、局部变量表大小(abstract 和 native 方法除外)
  6. 异常表(abstract 和 native 方法除外)
    • 每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引

静态变量关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分

全局常量(static final):
被声明为 final 的类变量的处理方法则不同,每个全局常量在编译的时候就会被分配了。

3. 运行时常量池

  • 方法区,内部包含了运行时常量池
  • 字节码文件,内部包含了常量池

一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外,还包含一项信息就是常量池表(Constant Pool Table),包括各种字面量和对类型方法符号引用

为什么需要常量池?
一个 java 源文件中的类、接口,编译后产生一个字节码文件。而 Java 中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里,换另一种方式,可以存到常量池,这个字节码包含了指向常量池的引用。在动态链接的时候会用到运行时常量池

常量池中有什么?
常量池内存储的数据类型包括:

  • 数量值
  • 字符串值
  • 类引用
  • 字段引用
  • 方法引用
    在这里插入图片描述
    常量池、可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型

运行时常量池

  • 运行时常量池(Runtime Constant Pool)是方法区的一部分。
  • 常量池表(Constant Pool Table)是 Class 文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
  • 运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。
  • 运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址
  • 运行时常量池,相对于 Class 文件常量池的另一重要特征是:具备动态性
  • 当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则 JVM 会抛 OutOfMemoryError 异常。

方法区使用举例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 方法区的演进细节

Hotspot 中方法区的变化: 在这里插入图片描述
在这里插入图片描述
为什么永久代要被元空间替代?:

  • 为永久代设置空间大小是很难确定的。在某些场景下,如果动态加载类过多,容易产生 Perm 区的 oom。比如某个实际 Web 工 程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。

    "Exception in thread 'dubbo client x.x connector' java.lang.OutOfMemoryError:PermGen space"
    

    而元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 因此,默认情况下,元空间的大小仅受本地内存限制。

  • 对永久代进行调优是很困难的。

StringTable 为什么要调整位置?:
jdk7 中将 StringTable 放到了堆空间中。因为永久代的回收效率很低,在 full gc 的时候才会触发。而 full gc 是老年代的空间不足、永久代不足时才会触发。

这就导致 StringTable 回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

静态变量存放在那里?:静态引用对应的对象实体始终都存在堆空间在这里插入图片描述

5. 方法区的垃圾回收

方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量不再使用的类型

判定一个常量是否“废弃”还是相对简单,而要判定一个类型是否属于“不再被使用的类”的条件就比较苛刻了。需要同时满足下面三个条件:

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类及其任何派生子类的实例。
  • 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如 OSGi、JSP 的重加载等,否则通常是很难达成的。
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

在大量使用反射、动态代理、CGLib 等字节码框架,动态生成 JSP 以及 OSGi 这类频繁自定义类加载器的场景中,通常都需要 Java 虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力

总结*:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/128076.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用百度“云一朵”来分析PDF文件

PDF 文件是一种常见的文件格式,用于存储文档、图像和其他内容。在许多情况下,我们需要对 PDF 文件进行分析,以提取其中的信息。百度“云一朵”提供了一个 PDF 分析 API,可以帮助我们轻松地对 PDF 文件进行分析。 在本博客文章中&…

qt开发从入门到实战2

以下是本人学习笔记 原视频:最新QT从入门到实战完整版|传智教育 qt开发从入门到实战1 练习示例 设计一个按钮,点击时弹出新窗口,再次点击时新窗口关闭 // exerciseQWidget* second_window new QWidget();QPushButton* btn3 new QPushBu…

【Java】微服务——Feign远程调用

目录 1.Feign替代RestTemplate1)引入依赖2)添加注解3)编写Feign的客户端4)测试5)总结 2.自定义配置2.1.配置文件方式2.2.Java代码方式 3.Feign使用优化4.最佳实践4.1.继承方式4.2.抽取方式4.3.实现基于抽取的最佳实践1…

Kettle连接数据库[MySQL]报错

在连接数据库页面填写完成后点击“测试” 报错信息: 错误连接数据库 [ETLqiangzi] : org.pentaho.di.core.exception.KettleDatabaseException: Error occurred while trying to connect to the databaseDriver class org.gjt.mm.mysql.Driver could not be found…

【好玩】如何在github主页放一条贪吃蛇

前言 🍊缘由 github放小蛇,就问你烧不烧 起因看到大佬github上有一条贪吃蛇扭来扭去,觉得好玩,遂给大家分享一下本狗的玩蛇历程 🥝成果初展 贪吃蛇 🎯主要目标 实现3大重点 1. github设置主页 2. git…

TCP VS UDP

程序员写网络程序,主要编写的应用层代码! 真正要发这个数据,需要上层协议调用下层协议,应用层要调用传输层,则传输层给应用层提供一组api,统称为:soket api 基于UDP的api 基于TCP的api 这两个协…

京东数据接口|电商运营中数据分析的重要性

在电商运营中,数据分析是非常重要的一环,它可以帮助电商企业更好地了解市场、了解消费者、了解产品、了解销售渠道等各种信息,从而制定更为科学有效的运营策略,提高销售效益。 数据方面用户可以直接选择使用数据接口来获取&#…

Synchronized的实现和锁升级

1.JVM是如何处理和识别Synchronized的? 我们从字节码角度分析synchronized的实现: Synchronized(锁对象){}同步代码块底层实现方式是monitorenter和monitorexit指令。 修饰普通同步方法时底层实现方式是执行指令会检查方法是否设置ACC_SYNCHRONIZED&am…

Legion Y9000X IRH8 2023款(82Y3)原装出厂OEM预装Windows11系统

lenovo联想电脑笔记本拯救者原厂win11系统镜像 下载链接:https://pan.baidu.com/s/15G01j7ROVqOFOETccQSKHg?pwdt1ju 系统自带所有驱动、出厂主题壁纸、Office办公软件、联想电脑管家等预装程序 所需要工具:32G或以上的U盘 文件格式:ISO…

Vue 3 学习 源码解读

该文章内容为以下视频的学习笔记: 前言_哔哩哔哩_bilibili前言是秋招解决方案:深入 Vue3 源码,带你彻底打通 Vue3 源码面试的第1集视频,该合集共计13集,视频收藏或关注UP主,及时了解更多相关视频内容。htt…

JVM上篇之虚拟机与java虚拟机介绍

目录 虚拟机 java虚拟机 简介 特点 作用 位置 整体结构 类装载子系统 运行时数据区 java执行引擎 Java代码执行流程 jvm架构模型 基于栈式架构 基于寄存器架构 总结 jvm的生命周期 1.启动 2.执行 3.退出 JVM的发展历程 虚拟机 所谓虚拟机,指的…

【微服务】RedisSearch 使用详解

目录 一、RedisJson介绍 1.1 RedisJson是什么 1.2 RedisJson特点 1.3 RedisJson使用场景 1.3.1 数据结构化存储 1.3.2 实时数据分析 1.3.3 事件存储和分析 1.3.4 文档存储和检索 二、当前使用中的问题 2.1 刚性数据库模式限制了敏捷性 2.2 基于磁盘的文档存储导致瓶…