JVM工作原理与实战(十九):运行时数据区-方法区

news2025/1/6 19:45:38

专栏导航

JVM工作原理与实战

RabbitMQ入门指南

从零开始了解大数据


目录

专栏导航

前言

一、运行时数据区

二、方法区

1.方法区介绍

2.方法区在Java虚拟机的实现

3.类的元信息

4.运行时常量池

5.字符串常量池

6.静态变量的存储

总结


前言

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了方法区、方法区在Java虚拟机的实现、类的元信息、运行时常量池、字符串常量池、静态变量的存储等内容。


一、运行时数据区

Java虚拟机(JVM)在运行Java程序期间,会创建并维护一系列内存区域,这些区域总称为运行时数据区。这些区域根据其用途和特性,被严格定义并管理。《Java虚拟机规范》详细规定了这些区域的作用和行为,以确保所有Java虚拟机实现的一致性和正确性。

线程不共享区域:

  • 程序计数器:用于存储当前线程执行的字节码指令地址。这个区域是每个线程独有的,不共享。
  • Java虚拟机栈:每个线程在创建时都会创建一个虚拟机栈,每个方法调用都会创建一个栈帧,用于存储局部变量、操作数栈、动态链接和方法出口信息。
  • 本地方法栈:与虚拟机栈相似,本地方法栈为native方法提供服务。

线程共享区域:

  • 方法区:用于存储已被JVM加载的类信息、常量、静态变量以及即时编译器编译后的代码等数据。
  • :堆是所有线程共享的区域,用于动态分配内存。所有的对象实例以及数组都应当在堆上分配。

二、方法区

1.方法区介绍

方法区是Java虚拟机中的一部分,用于存储已被虚拟机加载的类信息、常量、静态变量以及即时编译器编译后的代码等数据。这个区域的设计目标是为所有线程提供共享的、动态类型的数据。它的核心功能是支持类的加载和链接,以及提供运行时类型信息。

方法区主要由以下三部分构成:

  • 类的元信息(Class Metadata):这部分保存了关于类的所有基本信息。这些信息在类加载时被创建,并存储在方法区中。类的元信息包括类的名称、类的访问权限、类的字节码版本、父类的名称、实现的接口列表、字段和方法信息等。这些信息在运行时被JVM使用,以支持类的方法解析、反射操作和动态代理等功能。
  • 运行时常量池(Runtime Constant Pool):运行时常量池是方法区中的一个重要部分,它主要负责存储字节码文件中的常量池内容。常量池是字节码文件中的一个特殊部分,用于存储各种类型的常量,如字面量、类符号引用等。在运行时,JVM会根据需要动态地向常量池中添加、删除或修改相应的常量。此外,对于每个类,其常量池都有一个私有的副本,但所有线程共享同一个运行时常量池,以确保线程安全。
  • 字符串常量池(String Constant Pool):字符串常量池是运行时常量池的一部分,用于存储字符串字面量。在Java程序中,每个独特的字符串字面量都会在字符串常量池中创建一个相应的字符串对象。如果一个字符串字面量已经存在于常量池中,则不会创建新的对象,而是返回对已有对象的引用。这种设计可以有效地节省内存,并避免创建重复的字符串对象。

2.方法区在Java虚拟机的实现

方法区是Java虚拟机结构中的重要部分,它是《Java虚拟机规范》中定义的一个抽象概念。每款具体的Java虚拟机实现可能会根据规范进行不同的优化和调整。以HotSpot虚拟机为例,来探讨其实现细节。

在JDK7及更早的版本中,方法区被实现为永久代(PermGen)。它位于Java堆内存区域中,并通过虚拟机参数-XX:MaxPermSize来控制其最大大小。然而,这种实现方式在JDK8中被彻底改变。

从JDK8开始,方法区被移至元空间(Metaspace)中。元空间不再属于Java堆的一部分,而是直接建立在操作系统的本地内存中。这种设计使得元空间的大小不再受Java堆大小的限制,而是取决于本地内存的大小。可以通过虚拟机参数-XX:MaxMetaspaceSize可以设置元空间的最大大小。

在诊断和监控Java应用时,了解这些差异尤为重要。使用如Arthas这样的诊断工具,可以查看不同版本的Java虚拟机的内存使用情况。在JDK7中,需要关注ps_perm_gen属性来查看方法区的使用情况;而在JDK8及之后的版本,则需要查看metaspace属性。

案例:

为了模拟方法区的溢出情况,可以使用如ByteBuddy这样的框架动态生成大量的字节码数据,并观察方法区是否会出现内存溢出。

引入ByteBuddy依赖:

        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.12.23</version>
        </dependency>

编写测试案例:

public class Demo1 extends ClassLoader {
    public static void main(String[] args) throws IOException {
        System.in.read();
        Demo1 demo1 = new Demo1();
        int count = 0;
        while (true) {
            String name = "Class" + count;
            ClassWriter classWriter = new ClassWriter(0);
            classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null
                    , "java/lang/Object", null);
            byte[] bytes = classWriter.toByteArray();
            demo1.defineClass(name, bytes, 0, bytes.length);
            System.out.println(++count);
        }
    }
}

在JDK7上,执行十几万次操作就可能出现错误;而在JDK8上,尽管内存使用量会直线上升,但程序并不会出现错误。

3.类的元信息

方法区,也被称为元空间,是Java虚拟机中用于存储类的元数据信息的区域。这些元信息,通常被称为InstanceKlass对象,包含了关于类的基本信息,例如类的名称、父类的名称、实现的接口、成员变量和方法等。这些信息在类的加载阶段被完全建立并存储在方法区中。

InstanceKlass对象是类元信息的核心,它不仅包含了类的静态信息,如字段和方法,还包含了类的动态行为信息,如字节码信息和常量池等。这些信息在运行时被JVM用于支持诸如反射、动态类加载和异常处理等功能。

需要注意的是,方法区的实现和组织方式可能会因JVM的实现而有所不同。例如,在一些JVM实现中,方法区可能会被组织成一个或多个哈希表,以快速查找类的元信息。而在其他实现中,可能会使用其他数据结构或算法来组织和管理这些信息。

4.运行时常量池

在Java的内存区域中,方法区用于存储类的元数据信息。然而,除了存储类的元信息之外,方法区还包含了一个重要的部分:运行时常量池。

运行时常量池是Java虚拟机在运行时创建的一个数据结构,用于存储字节码中的常量池内容。常量池是字节码文件中的一个特殊部分,包含了程序中的常量值,例如字符串字面量、整数等。这些常量在字节码文件中通过编号索引的方式进行访问,这种常量池称为静态常量池。

当字节码文件被加载到内存中时,静态常量池的内容会被复制到运行时常量池中。与静态常量池不同,运行时常量池中的常量可以直接通过内存地址进行访问,因此具有更高的访问速度。这种运行时常量池的设计使得Java程序在运行时能够快速地访问和操作常量,提高了程序的执行效率。

5.字符串常量池

在运行时数据区的方法区中,除了类的元信息和运行时常量池外,还有一个特别重要的区域,那就是字符串常量池。字符串常量池主要负责存储字节码文件中定义的常量字符串内容。例如,在代码中定义的常量字符串“123”,这个字符串就会存放在字符串常量池中。

早期的设计中,字符串常量池被视为运行时常量池的一部分,它们共享相同的存储空间。然而,随着技术的进步和优化需求的变化,Java虚拟机对这两者的存储区域进行分离。这种调整的主要原因在于,字符串常量池和运行时常量池的功能和职责存在明显的差异。运行时常量池主要负责管理动态编译和类的加载,而字符串常量池则专注于存储和管理程序中定义的常量字符串。

6.静态变量的存储

在Java的运行时数据区中,静态变量(也称为类变量)的存储位置在不同版本的Java中有所不同。

在JDK 6及之前的版本中,静态变量是存放在方法区中的,确切地说,是在永久代(PermGen)中。然而,随着Java的发展,这个设计逐渐暴露出一些问题,例如内存溢出和空间限制等。

从JDK 7开始,Java对运行时数据区进行了重新设计,其中最显著的变化就是将静态变量从永久代移出,并存放在了堆内存中的Class对象中。这种变化不仅解决了永久代存在的问题,还使得静态变量的存储更加符合其作为类级别的变量的特性。每个Class对象都包含了该类的静态变量信息,这些信息随着类的加载而加载到内存中。这种设计使得静态变量的访问更加直接和高效,因为它们不再需要从方法区中查找,而是可以直接从Class对象中获取。


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了方法区、方法区在Java虚拟机的实现、类的元信息、运行时常量池、字符串常量池、静态变量的存储等内容,希望对大家有所帮助。

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

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

相关文章

【4k】4k的webrtc播放示例

目录 使用带研发角色的账号&#xff0c;在app端设置下分辨率 &#xff1a; 4k 点播 ffplay播放看下详细的参数 使用带研发角色的账号&#xff0c;在app端设置下分辨率 &#xff1a; 4k 点播 ffplay播放看下详细的参数

Gartner:2024年及未来中国网络安全重要趋势

Gartner于今日发布2024年及未来中国网络安全重要趋势。 Gartner高级研究总监高峰表示&#xff1a;“随着人工智能&#xff08;AI&#xff09;等重大技术突破的出现、工作方式的社会性变革以及地缘政治的转变都意味着技术采购可能必须完全在境内实施&#xff0c;且数据和系统可…

【前端HTML】HTML基础

文章目录 HTML标签标签属性 基本结构文档声明HTML标准结构HTML基础排版标签语义化标签块级元素与行内元素文本标签图片标签超链接跳转到指定页面跳转到文件跳转到锚点唤起指定应用 列表有序列表无序列表列表嵌套自定义列表 表格基本结构常用属性跨行跨列 常用标签表单基本结构常…

2024年甘肃省职业院校技能大赛信息安全管理与评估 样题三 模块一

竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 1.第一阶段&#xff1a;模块一 网络平台搭建与设备安全防护&#xff08;180 分钟&#xff0c;300 分&#xff09;。 2.第二阶段&#xff1a;模块二…

实验一 安装和使用Oracle数据库

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

【MYSQL】存储引擎MyISAM和InnoDB

MYSQL 存储引擎 查看MySQL提供所有的存储引擎 mysql> show engines; mysql常用引擎包括&#xff1a;MYISAM、Innodb、Memory、MERGE 1、MYISAM&#xff1a;全表锁&#xff0c;拥有较高的执行速度&#xff0c;不支持事务&#xff0c;不支持外键&#xff0c;并发性能差&#x…

springBoot项目打包发布

打包 项目代码编写完成后&#xff0c;在pom.xml文件中引用打包的插件&#xff1a; <!-- 打包插件坐标--><build><plugins><!--打包插件--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-mave…

Docker 容器连接

Docker 容器连接 前面我们实现了通过网络端口来访问运行在 docker 容器内的服务。 容器中可以运行一些网络应用&#xff0c;要让外部也可以访问这些应用&#xff0c;可以通过 -P 或 -p 参数来指定端口映射。 下面我们来实现通过端口连接到一个 docker 容器。 网络端口映射 …

Leetcode24-找到两个数组中的公共元素(2956)

1、题目 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;它们分别含有 n 和 m 个元素。 请你计算以下两个数值&#xff1a; 统计 0 < i < n 中的下标 i &#xff0c;满足 nums1[i] 在 nums2 中 至少 出现了一次。 统计 0 < i < m 中的下标 i &…

三、Sharding-JDBC系列03:自定义分片算法

目录 一、概述 1.1、分片算法 精确分片算法 范围分片算法 复合分片算法 Hint分片算法 1.2、分片策略 标准分片策略 复合分片策略 行表达式分片策略 Hint分片策略 不分片策略 二、自定义分片算法 - 复合分片算法 (1)、创建数据库和表 (2)、自定义分库算法 (3)、…

如何实现数据库读一致性

1 导读 数据的一致性是数据准确的重要指标&#xff0c;那如何实现数据的一致性呢&#xff1f;本文从事务特性和事务级别的角度和大家一起学习如何实现数据的读写一致性。 2 一致性 1.数据的一致性&#xff1a;通常指关联数据之间的逻辑关系是否正确和完整。 举个例子&#…

中北数据结构2023真题

雪雾: 设计一个算法&#xff0c;将一个节点值为自然数的单列表拆分成两个单列表&#xff0c;原表中值为偶数的节点保留&#xff0c;而值为奇数的节点&#xff0c;按他们在原表的相对次序组成一个新的单列表 #include <stdio.h> #include <stdlib.h>typedef struct…

Python算法例36 丑数Ⅱ

1. 问题描述 设计一个算法&#xff0c;找出只含素因子2、3、5的第n小的数&#xff0c;符合条件的数如&#xff1a;1、2、3、4、5、6、8、9、10、12… 2. 问题示例 如果n9&#xff0c;返回10。 3. 代码实现 def find_nth_number(n):if n < 0:return Nonenumbers [1]idx…

Python-基础篇-类与对象/面向对象程序设计

文章目录 思维导图是何物类定义类&#x1f4da; class类的成员&#x1f4da;类的继承性&#x1f4da;封装性&#x1f4da;多态性 对象面向对象&#x1f4da;创建对象&#x1f4da;销毁对象&#x1f4da; 类和对象关系必背必记专业英语学习角 思维导图 是何物 类 “类”是物以…

DotNET 8 新特性 - AoT 编译、 MinimalAPI、Json源生成器

AoT编译方式特性 裁剪减小体积&#xff0c;取消JIT编译&#xff0c;不使用反射技术。直接产生目标机器二进制代码&#xff0c;目前支持x86&#xff0c;解决被反编译问题。 使用本机 AOT 发布的应用&#xff1a;最大程度减少了磁盘占用空间缩短了启动时间减少了内存需求 | 功能…

springcloud +Vue 前后端分离的onlinejudge在线评测系统

功能描述&#xff1a; 本系统的研究内容主要是设计并实现一个一个在线测评系统&#xff08;OJ&#xff09;&#xff0c;该系统集成了博客、竞赛、刷题、教学&#xff0c;公告&#xff0c;个人管理六大功能&#xff0c;用户注册后登录系统&#xff0c;可以浏览本站的全部文章、发…

Nginx 简介

1、概念介绍 Nginx ("engine x") 是一个轻量级、高性能的 WEB 服务器软件和反向代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的&#xff0c;第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。其将源代码以类 BSD 许可证的形式发…

67.基于控制流编程,优化Go代码可读性

文章目录 一&#xff1a;简介二、代码整洁小技巧&#xff1a;基于控制流编程三、总结 代码地址&#xff1a;https://gitee.com/lymgoforIT/golang-trick/tree/master/40-clean-code-controll-flow 一&#xff1a;简介 如何写好代码&#xff0c;一千个人眼中有一千个哈姆雷特&…

Docker之nacos集群部署

前言 Nacos 是一个开源的注册中心和配置中心&#xff0c;用于实现微服务架构中的服务发现、服务治理和动态配置管理。在 Docker 中使用 Nacos&#xff0c;你可以通过拉取官方提供的 Docker 镜像并运行容器的方式来快速部署 一.Nacos镜像拉取及独立模式 镜像拉取命令详解&…

用3D渲染效果图时,需要注意什么?

要用3D渲染效果图&#xff0c;您需要使用3D建模软件来创建三维模型、材质、灯光和相机等元素&#xff0c;并使用渲染引擎将它们渲染成逼真的图像。那么用3D渲染效果图需要注意什么? 在用3D渲染效果图时&#xff0c;您需要注意以下几点&#xff1a; 1、模型精度&#xff1a;模型…