【JVM】运行时数据区之方法区——自问自答

开局从康师傅那里借图几张

 线程共享与私有

 

《Java虚拟机规范》中明确说明:“尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。” 但对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。
所以,方法区看作是一块独立于Java堆的内存空间.

方法区 (Method Area)与Java堆一样,是各个线程共享的内存区域。
方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。
方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误: java.lang.OutofMemoryError:PermGen space 或者 java.lang.OutofMemoryError: Metaspace

加载大量的第三方的jar包;

Tomcat部署的工程过多 (30-50个):

大量动态的生成反射类

在做插件管理的时候,类只加载而不卸载,运行时间久后就出现 OOM

关闭JVM就会释放这个区域的内存。

Q:方法区的演化

方法区,是JVM的规范 specification,具体不同的虚拟机有不同的实现方式。

比如JRocket使用的是本地内存,而JDK7及以前,使用的是永久代,JDK8把永久代换成了元空间。

这里我就不啰嗦了,可以参考JEP 122: Remove the Permanent Generation

简而言之HotSprot虚拟机在JDK7及以前,使用的是永久代,JDK8把永久代换成了元空间。永久代用的是JVM内的逻辑空间,而元空间使用的是本地内存。这一改动,与Orcale 收购JRocket虚拟机有关.

 

StringTable为什么要调整 ?

jdk7中将stringTable放到了堆空间中。因为永久代的回收效率很低,在full gc的时候才会触发。而full gc是老年代的空间不足、永久代不足时才会触发。这就导致stringTable回收效率不高。而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足。放到堆里,能及时回收内存。

不管怎么变,请注意以下原则:

所有的对象实例,都是放在堆中的,不管这个对象是局部的,static 还是其他对象。

对于静态对象,对象实例存在堆,而对象的引用是存放在 方法区的。(JDK7之后已经放在堆中)

同上面的结论,class对象也是存放在堆内的。

从《Java虚拟机规范》所定义的概念模型来看,所有class相关的信息都应该存放在方法区之中但方法区该如何实现,《Java虚拟机规范》并未做出规定,这就成了一件允许不同虚拟机自己灵活把握的事情。JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射class对象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点。

可以使用Inspector 来查看对象内存地址。

Q:内存泄漏 与内存溢出

Q:方法区的内部结构

它用于存储已被虚拟机加载的类型信息常量静态变量即时编译器编译后的代码缓存等。

这里再提及一点,从JDK7之后,把字符串常量池,静态变量的实际存储位置放到了堆内

这点也说明了,方法区在逻辑上是连续的,但是在物理上是可以离散存储的。

1、类型信息:

对每个加载的类型(类class、接门interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:
1、这个类型的完整有效名称 (全名=包名.类名)
2、这个类型直接父类的完整有效名(对于interface或是java.lang.object,都没有父类)

3、这个类型的修饰符(public,abstract, final的某个子集)
4、这个类型直接接口的一个有序列表

2、域信息

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

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

3、方法(Method)信息


JVM必须保存所有方法的以下信息,同域信息一样包括声明顺序 :
方法名称


方法的返回类型(或 void)


方法参数的数量和类型(按顺序)


方法的修饰符(public,private,protected,static, final,synchronized,native, abstract的一个子集)


方法的字节码(bytecodes)、操作数栈、局部变量表及大小 (abstract和native方法除外)


异常表(abstract和native方法除外)

        > 每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引

no-final的类变量(即所谓的静态变量)

它是与类关联的,随着类加载而加载,在Linking的准备阶段被赋予默认值,在Initialization阶段 执行类<clint>方法,获得最终值。它是存在于方法区的(JDK7之后,逻辑上属于方法区,物理上被移到了 堆内)。

全局常量:static final

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

4、运行时常量池 VS 常量池

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

要弄清楚方法区,需要理解清楚classFile,因为加载类的信息都在方法区要弄清楚方法区的运行时常量池,需要理解清楚classFile中的常量池。如下:

具体参考:

The Class File Format

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

借康师傅的PPT

运行时常量池 (Runtime Constant Pool) 是方法区的一部分。


常量池表 (constant Pool Table) 是class文件的一部分,用于存放编译期生成的各种字面量与符号引用这部分内容将在类加载后存放到方法区的运行时常量池中

运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。

JVM为每个已加载的类型 (类或接口) 都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。
运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这
里换为真实地址。

        > 运行时常量池,相对于class文件常量池的另一重要特征是:具备动态性。

运行时常量池类似于传统编程语言中的符号表 (symbol table),但是它所包含的数据却比符号表要更加丰富一些。


当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则JVM会抛OutofMemoryError异常。

 回忆一下:类加载linking的第三补,resolve解析。就是把常量池的符号引用转换成地址引用

Q: 方法区的垃圾回收

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

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

相关文章

Vue之ElementUI之动态树+数据表格+分页(项目功能)

目录 前言 一、实现动态树形菜单 1. 配置相应路径 2. 创建组件 3. 配置组件与路由的关系 index.js 4. 编写动态树形菜单 5. 页面效果演示 二、实现数据表格绑定及分页功能 1. 配置相应路径 2. 编写数据表格显示及分页功能代码 BookList.vue 3. 演示效果 总结 前言…

vue 普通组件的 局部注册

vue 普通组件的 注册 11 Vue2_3入门到实战-配套资料\01-随堂代码素材\day03\素材\00-准备代码\小兔鲜首页静态页\src

蓝桥杯每日一题20223.9.26

4407. 扫雷 - AcWing题库 题目描述 分析 此题目使用map等都会超时&#xff0c;所以我们可以巧妙的使用哈希模拟散列表&#xff0c;哈希表初始化为-1首先将地雷读入哈希表&#xff0c;找到地雷的坐标在哈希表中对应的下标&#xff0c;如果没有则此地雷的位置第一次出现&#…

MySQL基础篇-约束

目录 1.约束概述 2.分类 3.测试user表的约束情况 主键约束 非空约束及唯一约束 检查约束 默认约束 4.外键约束 外键约束的语法 外键约束的删除/更新行为 小结 1.约束概述 MySQL约束&#xff08;Constraints&#xff09;是用于确保表中数据完整性和一致性的规则。它们定…

vue3 + mark.js | 实现文字标注功能

页面效果 具体实现 新增 1、监听鼠标抬起事件&#xff0c;通过window.getSelection()方法获取鼠标用户选择的文本范围或光标的当前位置。2、通过 选中的文字长度是否大于0或window.getSelection().isCollapsed (返回一个布尔值用于描述选区的起始点和终止点是否位于一个位置&…

2.(vue3.x+vite)组件注册并调用

前端技术社区总目录(订阅之前请先查看该博客) 关联博客 1.(vue3.x+vite)封装组件 一:umd调用方式 1:引入umd.js <script src="./public/myvue5.umd.js"></script>2:编写代码调用 (1)umd方式,根据“5

爬虫 — 多线程

目录 一、多任务概念二、实现多任务方式1、多进程 &#xff08;Multiprocessing&#xff09;2、多线程&#xff08;Multithreading&#xff09;3、协程&#xff08;Coroutine&#xff09; 三、多线程执行顺序四、多线程的方法1、join()2、setDaemon()3、threading.enumerate() …

Vue+ElementUI实现动态树和表格数据的分页模糊查询

目录 前言 一、动态树的实现 1.数据表 2.编写后端controller层 3.定义前端发送请求路径 4.前端左侧动态树的编写 4.1.发送请求获取数据 4.2.遍历左侧菜单 5.实现左侧菜单点击展示右边内容 5.1.定义组件 5.2.定义组件与路由的对应关系 5.3.渲染组件内容 5.4.通过动态…

Denoising diffusion implicit models 阅读笔记

Denoising diffusion probabilistic models (DDPMs)从马尔科夫链中采样生成样本&#xff0c;需要迭代多次&#xff0c;速度较慢。Denoising diffusion implicit models (DDIMs)的提出是为了加速采样过程&#xff0c;减少迭代的次数&#xff0c;并且要求DDIM可以复用DDPM训练的网…

lv5 嵌入式开发-7 有名管道和无名管道

目录 1 进程间通信介绍 2 无名管道 2.1 无名管道特点 ​编辑 2.2 读无名管道 2.3 写无名管道 3 有名管道 3.1 有名管道特点 3.2 写有名管道 3.3 读有名管道 掌握&#xff1a;进程间通信方式介绍、无名管道特点、无名管道创建、无名管道读写特性&#xff1b;有名管道…

深入浅出DAX:SELECTEDVALUE()

深入浅出DAX&#xff1a;SELECTEDVALUE() SELECTEDVALUE()&#xff0c;如果筛选 columnName 的上下文后仅剩下一个非重复值&#xff0c;则返回该值。否则返回alternateResult&#xff0c;语法如下&#xff1a; SELECTEDVALUE(<columnName>[, <alternateResult>] …

Rabbit消息的可靠性

生产者重连 消费者重试 Confirm模式简介 消息的confirm确认机制&#xff0c;是指生产者投递消息后&#xff0c;到达了消息服务器Broker里面的exchange交换机&#xff0c;则会给生产者一个应答&#xff0c;生产者接收到应答&#xff0c;用来确定这条消息是否正常的发送到Broker…

【大数据】Doris 构建实时数仓落地方案详解(三):Doris 实时数仓设计

本系列包含&#xff1a; Doris 构建实时数仓落地方案详解&#xff08;一&#xff09;&#xff1a;实时数据仓库概述Doris 构建实时数仓落地方案详解&#xff08;二&#xff09;&#xff1a;Doris 核心功能解读Doris 构建实时数仓落地方案详解&#xff08;三&#xff09;&#…

数据库存储引擎和数据类型详细介绍

目录 一、数据库存储引擎&#xff08;了解&#xff09;1.了解MySQL体系结构2.存储引擎&#xff08;了解&#xff09;2.1.存储引擎的介绍2.2.存储引擎分类2.3.如何选择引擎&#xff1f; 3.事务控制语言(TCL)事务的四个特性(ACID) 二、数据类型&#xff08;了解&#xff09;1.整型…

Servlet操作与用法(保姆式教学)

Servlet介绍 什么是servlet Servlet&#xff08;Servlet Applet的缩写&#xff0c;全称 Java Servlet&#xff09;&#xff1a;适用于Java编写的服务器程序&#xff0c;其主要功能是在于交互式的浏览和修改数据&#xff0c;生成动态Web内容。狭义的Servlet是指Java语言实现的…

Xmake v2.8.3 发布,改进 Wasm 并支持 Xmake 源码调试

Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量&#xff0c;没有任何依赖&#xff0c;因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建&#xff0c;相比 makefile/CMakeLists.txt&#xff0c;配置语法更加简洁直观&#xff0c;对新手非常友好&#x…

ARM day1

1.复习今日内容 2.搭建汇编环境 下发资料-》工具软件 -》汇编环境搭建 3.安装Ubuntu下的交叉编译工具链 思维导图&#xff1a;

latexocr安装过程中遇到的问题解决办法

环境要求&#xff1a;需要Python版本3.7&#xff0c;并安装相应依赖文件 具体的详细安装步骤可见我上次写的博文&#xff1a;Mathpix替代者|科研人必备公式识别插件|latexocr安装教程 ‘latexocr‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件的相关解决办…

十五、异常(2)

本章概要 自定义异常 异常与记录日志 异常声明 自定义异常 不必拘泥于 Java 已有的异常类型。Java异常体系不可能预见你将报告的所有错误&#xff0c;所以你可以创建自己的异常类&#xff0c;来表示你的程序中可能遇到的问题。 要自己定义异常类&#xff0c;必须从已有的异…

什么是 Redis?

Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成的&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列&#xff0c;分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景&#xff0c;比如 String(字符串)、Has…