JVM内存模型理解

news2024/12/30 2:13:46
1、首先理解下什么是 jvm 内存模型?

jvm内存模型定义了Java虚拟机运行时如何组织和管理内存,规定了各个内存区域的作用、结构和交互方式,以及线程间的内存可见性、内存操作的原子性等行为,以支持Java程序的执行,即一种约束或规定

2、内存区域划分及作用
a、栈(Stack)

       用于存储方法的调用和局部变量,每个方法在调用时都会创建一个栈帧,栈帧包含方法的参数、局部变量以及部分运行时数据。方法的调用及返回则对应栈帧的入栈和出栈

局部变量表:局部变量表用于存储方法中的局部变量。它包含了方法的参数以及方法内部定义的局部变量。局部变量表中的每个变量都在编译时确定其类型和内存位置。

操作数栈:操作数栈用于存储方法执行过程中的操作数和中间结果。它是一个后进先出(LIFO)的数据结构,方法的操作数和计算结果通过操作数栈进行传递。

动态链接:栈帧中包含一个指向运行时常量池中方法的具体位置的引用,用于实现方法的动态绑定。动态链接在方法调用时确定所调用的方法。

返回值地址:栈帧中存储了方法执行完毕后的返回地址,用于指示程序在方法执行结束后继续执行的位置。

b、堆(Heap)

        虚拟机内存管理的绝对核心,提供了动态分配和回收内存的机制,用于存储Java程序中创建的对象实例和数组

新生代(Young Generation):分为Eden空间、Survivor空间,JVM 最大的一块内存空间

  • Eden空间:是新创建对象的初始分配区域。大多数对象在被创建后都会被分配到Eden空间。

  • Survivor空间:当Eden空间中的对象经过一次垃圾回收后仍然存活,它们会被移动到Survivor空间。Survivor空间通常有两个,其中一个是空的,用于垃圾回收时进行对象复制。

老年代(Old Generation):用于存储生命周期较长的对象。当对象在新生代经过多次垃圾回收仍然存活时,会被移送到老年代。 age > 15 会进入老年代,是因为HotSpot在对象头中的标记字段分配的空间为4位,最多只能记录到15 (对应虚拟机参数 -XX:+MaxTenuringThreshold)

TLAB(thread local allocation buffer):线程私有的,为了减少多线程环境下的锁竞争,提高对象分配的性能而引入的优化技术。一种针对多线程环境下对象分配的优化策略。 不同的Java虚拟机实现 TLAB 可能会有不同的默认值。一般情况下,默认的TLAB大小是相对较小的,通常在几十KB到几百KB之间。在大多数情况下,线程可以直接在自己的TLAB中进行对象分配,无需竞争TLAB。可能需要竞争TLAB的情况:

  • 线程的TLAB已满:线程的TLAB用尽,它需要重新分配一个新的TLAB。这个过程可能需要进行锁竞争,以确保线程可以安全地获取新的TLAB。

  • 大对象分配:TLAB通常用于分配小对象,而较大的对象可能无法在TLAB中容纳。当线程需要分配较大的对象时,它可能无法在自己的TLAB中完成分配,而需要在堆上进行分配。在这种情况下,线程可能需要竞争全局的堆锁或其他锁来进行对象分配。

  • GC(垃圾回收)期间的TLAB分配:当进行垃圾回收时,JVM可能需要重新分配和回收TLAB。这个过程可能需要进行锁竞争,以确保在进行垃圾回收的同时,其他线程可以安全地分配对象。

c、方法区(Method Area)

       用于存储类结构信息、常量、静态变量、即时编译器编译后的代码等数据的内存区域。方法区是线程共享的,用于支持多个线程的并发访问。  

class常量池(Class Constant Pool):存储编译时生成的字面量和符号引用。包含了类中的常量、字段和方法的符号引用,这些符号引用在类加载时被解析为直接引用(在类加载和链接阶段使用)

  • 字面值(Literal):指直接出现在代码中的常量值,例如整数、浮点数、字符、字符串、布尔值等。在编译阶段,编译器会将这些字面值的值存储在常量池中。例如,对于代码 int num = 10;,数字 10 就是一个字面值。
  • 符号引用(Symbolic Reference):指在编译阶段无法确定具体内存地址的引用,它包含了对类、方法、字段等符号的引用。在常量池中,符号引用以符号的形式存储,包括类的全限定名、方法的名称和描述符、字段的名称和描述符等。符号引用作为一种符号化的引用形式,可以在编译时进行跨模块的引用,而不需要指定具体的内存地址。
  • 直接引用(Direct Reference):指直接指向内存中某个对象、方法或字段的指针、句柄或其他引用形式。运行时通过解析符号引用,转换为具体的直接引用,虚拟机可以定位到具体的内存地址,并进行方法调用、字段访问等操作。

运行时常量池(Runtime Constant Pool):存储经过解析的符号引用对应的直接引用。在类加载时,类的符号引用会被解析为直接引用,存储在运行时常量池中供程序在运行时使用(在类的实例化、方法调用等运行时操作中使用)

       类的加载是在第一次使用该类时进行的,虚拟机为了防止多个线程同时加载同一个类,会对类加载过程进行同步处理(类加载的同步)。在类加载的过程中,会通过加锁机制保证同一时间只有一个线程可以加载该类。其他线程在等待时,会被阻塞或进入等待状态。

d、程序计数器(Program Counter,PC)

       用于记录当前线程执行的字节码指令位置,实现分支控制、循环控制、异常处理和线程切换恢复等功能。程序计数器的正确性和准确性对于程序的正确执行非常关键。

e、本地方法(Native Method)

       用于支持执行本地方法(Native Method)的线程调用。本地方法是使用非Java语言(通常是C或C++)编写的方法,通过Java本地接口(JNI)与Java代码进行交互。

本地方法栈与Java虚拟机栈类似,每个线程都有自己的本地方法栈。它们的主要区别是,Java虚拟机栈用于支持Java方法的调用和执行,而本地方法栈用于支持本地方法的调用和执行。

3、方法区的不同实现

    a、因为虚拟机的多样性,不同的Java虚拟机按照规定或约束对方法区的实现也存在一些差异

Java 7及之前版本,通常采用永久代(Permanent Generation)作为方法区的实现方式,该区域使用固定大小的内存空间存储类的元数据、字节码和常量池等信息。然而,永久代的大小固定且无法动态调整,垃圾回收机制相对简单,可能导致内存溢出问题。

Java 8及之后版本,永久代被元空间(Metaspace)所取代,成为主流的方法区实现方式。元空间使用本地内存实现,将类的元数据存储在本地内存中。相比永久代,元空间的大小可以动态调整,避免了永久代内存溢出的问题,并利用操作系统的虚拟内存机制,减轻了内存管理的压力。值得注意的是Java 8及之后版本的元空间将一部分内容从方法区中移出,例如运行时常量池中的符号引用和字符串常量。这些内容被移到了堆中或者本地内存中。

Java 9及之后版本,引入了元空间的元数据共享特性,允许多个Java虚拟机进程共享元数据,进一步减少内存占用。

     b、存储内容的区别

永久代(Permanent Generation):

  • 类的元数据:包括类的名称、父类、接口、字段和方法等信息。
  • 字节码:类的字节码指令。
  • 运行时常量池:存储类的常量。
  • 静态变量:类的静态字段。

元空间(Metaspace):

  • 类的元数据:包括类的名称、父类、接口、字段和方法等信息。
  • 字节码:类的字节码指令。
  • 运行时常量池:存储类的常量。
  • 符号引用:包括类的符号引用、方法的符号引用等。
  • 字符串常量:存储字符串常量。
  • 静态变量:类的静态字段。

      永久代和元空间存储的内容是非常相似的,主要包括类的元数据、字节码、运行时常量池和静态变量等。

       唯一的区别在于元空间还存储了符号引用,用于引用类、方法、字段等。符号引用在运行时可以解析为直接引用,从而实现动态链接和类加载的过程。此外,元空间还可以存储字符串常量,即类中的字符串字面量。

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

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

相关文章

以角色为基础的软件开发团队建设

角色抽象作为一种载体,可以很好地进行软件工程知识体系和企业知识地图的组织,满足企业知识体系持续改进的需要,因此角色团队组建和建设也可以作为软件工程实施方法之一。 软件开发项目立项时,重要工作之一就是开发团队的组建&…

Spring Security 6.x 系列(13)—— 会话管理及源码分析(一)

一、会话概念 在实现会话管理之前,我们还是先来了解一下协议和会话的概念,连协议和会话都不知道是啥,还谈啥管理。 1.1 http 协议 因为我们现在的会话,基本上都是基于HTTP协议的,所以在讲解会话之前,我再…

openmediavault(OMV) (26)网络(1)ddns-go

简介 "ddns-go" 是一个动态域名解析(Dynamic DNS)工具,用于更新域名的IP地址。它可以自动检测你的公共IP地址,并将其更新到指定的域名解析服务商,以确保你的域名始终与最新的IP地址相匹配。 安装 hub.docker.com上下载ddns-go镜像 配置compose文件 --- versio…

使用 Process Explorer 和 Windbg 排查软件线程堵塞案例分享

目录 1、问题说明 2、线程堵塞的可能原因分析 3、使用Windbg和Process Explorer确定线程中发生了死循环 4、根据Windbg中显示的函数调用堆栈去查看源码,找到问题 4.1、在Windbg定位发生死循环的函数的方法 4.2、在Windbg中查看变量的值去辅助分析 4.3、是循环…

ModStartCMS v7.9.0 内容推荐支持,用户授权升级

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用,支持后台一键快速安装,让开发者能快的实现业务功能开发。 系统完全开源,基于 Apache 2.0 开源协议,免费且不限制商业使用。 功能特性 丰富的模块市…

CMake入门教程【基础篇】HelloCMake

文章目录 概述核心实现代码示例使用技巧注意事项 总结 概述 CMake是一个强大的跨平台构建系统,广泛用于C和C项目。它使用简单的配置文件来生成标准的构建文件,从而使得构建过程跨平台且易于管理。本教程将通过一个“Hello World”示例(命名为…

必看 | 如何用「八爪鱼RPA」搬迁旧帮助中心站点到「HelpLook」?

对于工具类产品而言,帮助中心的搭建是非常重要的:一个好用的帮助中心,不仅可以帮助用户快速找到所需内容,提升用户的满意度;还可以减轻客服人员的压力,为公司节约大量的人力资源。 以八爪鱼采集器的帮助中心…

【Leetcode】466. 统计重复个数

文章目录 题目思路代码 题目 466. 统计重复个数 思路 题目要求找出一个最大整数 m,使得经过 n2 个字符串 s2 组成的字符串能够被经过 n1 个字符串 s1 组成的字符串完全包含的次数。使用动态规划来记录每个位置匹配的情况,并通过循环节的分析来计算最…

安全数据交换系统:有效提升网间文件交换能力

各级政府部门和金融、能源、电力这些行业,以及一些大中型企业组织,为了保护内部的重要数据不外泄,普遍都采用了多网络并行的方式,也是做了网络隔离划分,不同的网络拥有不同的密级以及人员权限。然后再通过安全数据交换…

C++Qt6 哈夫曼编码求解 数据结构课程设计 | JorbanS

一、 问题描述 在进行程序设计时,通常给每一个字符标记一个单独的代码来表示一组字符,即编码。在进行二进制编码时,假设所有的代码都等长,那么表示 n 个不同的字符需要 位,称为等长编码。如果每个字符的使用频率相等&…

系列七、Ribbon

一、Ribbon 1.1、概述 Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具,是Netflix发布的一款开源项目,其主要功能是提供客户端的软件负载均衡算法和服务调用,Ribbon客户端组件提供一系列完善的配置项,例如&#xff1a…

免费证书Let’s Encrypt

免费SSL证书是一种用于保护网站数据传输安全的加密技术。它能够确保用户与网站之间的信息传输是加密的,防止被黑客窃取或篡改。随着网络安全意识的提高,越来越多的网站开始使用SSL证书来保护用户的隐私和数据安全。 在过去,SSL证书需要购买才…

OpenAI官方发布ChatGPT 提示词指南,六大策略让你玩转大语言模型!

OpenAI前段时间官方放出了自己的提示工程指南,从大模型小白到开发者,都可以从中消化出不少营养。看看全世界最懂大模型的人,是怎么写提示词的。官方给出了6 个大提示策略: 1、清晰的指令: 告诉AI你具体想要什么。比如…

ElasticSearch的DSL查询语法解析

Elasticsearch提供了基于ISON的DSL (Domain Specific Lanquage)来定义查询。 目录 一、常见查询类型 二、DSLQuery基本语法 三、全文检索查询 3.1 match查询:会对用户输入内容分词,常用于搜索框搜索 ,语法: 3.2 multi match…

RK3568 学习笔记 : 解决 linux_sdk 编译 python 版本报错问题

前言 最近买了 【正点原子】 的 RK3568 开发板,下载了 开发板的资料,包括 Linux SDK,这个 Linux SDK 占用的空间比较大,扩展了一下 VM 虚拟机 ubuntu 20.04 的硬盘空间,编译才正常通过。 编译 RK3568 Linux SDK 时&am…

STM32存储左右互搏 SPI总线读写FRAM MB85RS2M

STM32存储左右互搏 SPI总线读写FRAM MB85RS2M 在中低容量存储领域,除了FLASH的使用,,还有铁电存储器FRAM的使用,相对于FLASH,FRAM写操作时不需要预擦除,所以执行写操作时可以达到更高的速度,其…

Postgresql源码(119)PL/pgSQL中ExprContext的生命周期

前言 在PL/pgSQL语言中,执行任何SQL都需要通过SPI调用SQL层解析执行,例如在SQL层执行表达式的入口: static bool exec_eval_simple_expr(PLpgSQL_execstate *estate,PLpgSQL_expr *expr,Datum *result,bool *isNull,Oid *rettype,int32 *re…

RK3568驱动指南|第九篇 设备模型-第95章 创建属性文件并实现读写功能实验1

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

《PySpark大数据分析实战》-23.Pandas介绍DataFrame介绍

📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…

STM32H5XX和STM32H7XX选型对比

文章目录 STM32H563/H573STM32H743/753对比内核不同H5独有安全管理器H7的外设资源更丰富 STM32H563/H573 STM32H563和STM32H573微控制器扩展了STM32高性能产品组合。这两款微控制器具有增强的性能和安全性、更高的能效和更多的片内外设。 STM32H563/573产品系列提供1至2 MB的…