JVM内存模型深度解读

        JVM(Java Virtual Machine,Java虚拟机)对于Java开发者和运行 Java 应用程序而言至关重要。其重要性主要体现在跨平台性、内存管理和垃圾回收、性能优化、安全性和稳定性、故障排查与性能调优等方面。今天就下学习一下 JVM 的内存模型。

一、JVM内存模型

        JVM 内存模型(Java Virtual Machine Memory Model,简称JMM)是 Java 虚拟机规范定义的一种内存结构组织方式,用于规定 Java 程序在 JVM 中的运行时数据区域划分以及它们之间的关系。它不仅描述了如何划分内存区域,还规定了线程如何访问这些内存区域以及线程间的通信规则。JMM 如下图:

        JVM内存模型主要分为程序计数器、Java虚拟机栈、本地方法栈、堆、方法区、运行时常量池、直接内存,下面来分别看下。

二、程序计数器

         程序计数器(Program counter Register)是一块较小的内存空间,它可以看做是当前线程所执行字节码的指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条要执行的字节码指令,它是程序流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要这个计数器来完成。每条线程独立拥有程序计数器,各线程之间计数器互不影响。

        如果线程正在执行 java 方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是本地(native)方法,这个计数器值则应为空。程序计数器是唯一一个在《Java虚拟机规范》中没有规定任何 OutOfMemeryError 情况的区域。

 三、 java虚拟机

        与程序计数器一样,java 虚拟机栈也是线程私有的,他的生命周期与线程一样。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,java虚拟机都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法的出口等信息。每一个方法在虚拟机栈中的执行完毕过程,就对应这一个栈帧从入栈到出栈的过程。

        局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(byte、short、char、int 、float、double、long、boolean)、对象引用(refrence类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象句柄或者其他与此对象相关的位置)和returnAddress类型。

        下面看一个例子

public class Test {public static int cacl() {int a = 1;int b = 2;int c = (a + b) * 10;return c;}public static void main(String[] args) {int cacl = cacl();System.out.println(cacl);}}

        局部变量表是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。

        操作数栈是一个先进后出的栈,当一个方法刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种各样的字节码指令往操作数栈中写入和提取,也就是出栈和入栈。

        动态链接,每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。Class文件中的常量池存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。

四、 本地方法栈

        本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用非常相似,其区别只是虚拟机栈为虚拟机执行 java 方法服务,而本地方法栈则是为虚拟机使用本地方法服务。

五、 堆

        Java 堆(Java Heap)是虚拟机所管理的内存最大的一块。java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的是存放对象实例。

        new 出来的对象是放到了 Eden 区,老年代默认占整个堆的 2/3 空间。JVM的分代理论中什么条件下会从新生代晋升到老年代?

  1. 默认情况下,对象经历了15次 minor gc,年龄变为15就会变为老年代。
  2. 假如说当前放对象的Survivor 区域里一批对象的总大小大于了这块 Survivor 区域的内存大小的50% ,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代了。
  3. 一些大对象在创建是也会放到老年代。老年代的包括一些链接,比如连接池等。

六、 方法区

        方法区(Method Area)与 java 堆一样是线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态常量、及时编译器编译后的代码缓存等数据。方法区是JVM的一个逻辑部分,具体实现在java7之前时永久代,Java8之后是元空间。

        那元空间和永久代有什么区别呢?

        JDK8 及以后把类的元数据放在本地内存中,这一块区域叫做 Metaspace,该区域在 jdk7 及以前是属于永久代的,元空间和永久代都是用来存储 class 相关信息,包括 class 对象的method、field 等。元空间和永久代其实都是方法区的实现,只是实现不同,所以说方法区只是JVM的规范。

        当前的主流框架,如 spring 等对类进行增强时都会使用 CgLib 等字节码技术,当增强的类越多,就需要越大的方法区,以保证动态生成的新类能载入内存。经常在运行时生成大量动态类的应用场景,应特别注意这些类的回收情况。

        在 java7 之后,原先位于方法区里的字符串常量池也被移到了堆中。并在 Java8 中使用元空间代替了永久代。这一替代最大的区别是元空间使用的是本地内存,而永久代使用的是 jvm 内存,使用本地内存的好处是J ava.lang.outofMemoryError:PermGen Space 将不复存在,只受限于本地内存大小的限制,解决了空间不足的问题,不过也不可能任其无限大,jvm在默认运行时会根据需要动态的设置其大小,这一替换的好处如下:

  • 字符串常量池在永久代中容易出现性能问题和内存溢出问题。
  • 类的方法信息大小难以确定,因此给永久代的大小指定带来了困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。永久代会为 GC 带来不必要的复杂性,并且回收效率偏低,在永久代中元数据可能会随着每一次 full gc 发生而进行移动,而 hotspot 虚拟机每种类型的垃圾回收器都要特殊处理永久代中的元数据,分离出来后可以简化 full gc。

        如下为永久代合堆的存储位置

七、 运行时常量池

        运行时常量池(Runtime Constant Pool)是方法区的一部分。class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项常量池,用于存放编译器生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池。

        运行期间也可以将新的常量放入池中,比如String的intern()方法

八、 直接内存

        直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《java虚拟机规范》中定义的内存区域。但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常的出现。

        在 JDK1.4 中新加入的 NIO 类,引入了一种基于通道(channel)与缓存区(Buffer)的 I/O方式,它可以使用 Native 函数库直接分配内存,然后通过一个存储在 Java 堆里面的DirecByBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提升性能,因为避免了在 java 堆和 native 堆中来回复制数据。

        显然,本地直接内存分配不受 java 堆大小的限制,但是既然是内存,则肯定还是会受到本机总内存大小及处理器寻址空间的限制。

        因为通常的垃圾收集日志等记录,并不包含 Direct Buffer 等信息,所以 Direct Buffer 内存诊断也是个比较头疼的事情,在JDK 8 之后的版本,可以方便的使用 Native Memory Tracking(NMT) 特性来诊断,可以在程序启动时增加下面的参数:

-XX:NativeMemoryTracking={summary|detail}

        注意,激活NMT通常会导致JVM 5%~10%的性能下降,需要慎重使用。

        总结:了解了JVM的内存模型后才能更好的理解对象创建、垃圾回收等等功能,后续将继续介绍这部分内容。

往期经典推荐

实时数据传输的新里程——Server-Sent Events(SSE)消息推送技术-CSDN博客

SpringBoot项目并发处理大揭秘,你知道它到底能应对多少请求洪峰?_springboot并发处理-CSDN博客

领航分布式消息系统:一起探索Apache Kafka的核心术语及其应用场景-CSDN博客

Redis性能大挑战:深入剖析缓存抖动现象及有效应对的战术指南_redis 缓存抖动怎么解决-CSDN博客

MySQL中order by原来是这么工作的-CSDN博客

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

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

相关文章

嵌入式学习40-数据结构

数据结构 1.定义 一组用来保存一种或者多种特定关系的 数据的集合(组织和存储数据) 程序的设计: …

31-Java前端控制器模式(Front Controller Pattern)

Java前端控制器模式 实现范例 前端控制器模式(Front Controller Pattern)是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理该处理程序可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给…

使用RabbitMQ,关键点总结

文章目录 1.MQ的基本概念2.常见的MQ产品3.MQ 的优势和劣势3.1 优势3.2 劣势 4.RabbitMQ简介4.1RabbitMQ 中的相关概念 1.MQ的基本概念 MQ全称 Message Queue(消息队列),是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信。…

掌握FL Studio21的编曲功能,让你的音乐创作更上一层楼

音乐是人类最美好的语言,它能够跨越国界、文化和语言,将人们紧密地联系在一起。在当今数字化时代,音乐创作已经不再是专业人士的专利,越来越多的音乐爱好者开始尝试自己动手制作音乐。而FL Studio21中文版编曲软件正是这样一个为你…

pdf文件属性的删除

pdf文件属性的删除 投标过程中需要处理文件属性,特别是word文件属性以及pdf文件的处理 这里讲解pdf文件属性的处理 word处理在我的另外一个博客中,word文件属性的处理 https://ht666666.blog.csdn.net/article/details/134102504 一般用 adobe acroba…

数字人解决方案——ER-NeRF实时对话数字人论文解读

简介 本文提出了一种新的基于条件神经辐射场(Condition NeRF)的talking portrait合成框架ER-NeRF,能够在较小的参数量下实现高精度的实时渲染和快速收敛。该方法利用空间区域的不平等贡献来指导谈话肖像建模,以提高动态头部重建的…

MNN 围炉札记

文章目录 一、MNN 资料二、使用示例三、源码分析1、createFromFile、createFromBuffer1.1 Content1.2 createFromBufferInternal1.3 Net1.4 Interpreter1.5 Interpreter::Interpreter 2、createRuntime2.1 RuntimeInfo2.2 Schedule::getApprociateType2.2.1 MNNGetExtraRuntime…

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020 前言简介模型架构共情生成器交互鉴别器损失函数前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《EmpDG: Multi-resolution Interactive E…

Linux 文件系统:文件描述符、管理文件

目录 一、三个标注输入输出流 二、文件描述符fd 1、通过C语言管理文件—理解文件描述符fd 2、文件描述符实现原理 3、文件描述符0、1、2 4、总结 三、如何管理文件 1、打开文件的过程 2、内核空间的结构 struct task_struct(PCB) struct file…

你真的了解SpringBoot注解?阿里巴巴面试告诉你答案!

如有疑问或者更多的技术分享,欢迎关注我的微信公众号“知其然亦知其所以然”! 大家好,我是小米!今天我来和大家分享一下在阿里巴巴面试中常见的一个问题:SpringBoot注解。SpringBoot作为当今流行的Java开发框架,注解是其灵魂所在,熟练掌握这些注解对于应对面试非常有帮…

腾讯云服务器入站规则端口开放使用指南(CentOS系统)

第一步:开放安全组入站规则 来源处0.0.0.0/0是对IPv4开发,::/0是对IPv6开放; 协议端口按照提示填写即可。云服务器防火墙开放 第三步:本地防火墙开放 sudo firewall-cmd --zonepublic --add-port你的端口号/tcp --perma…

【c++】类和对象

主页:醋溜马桶圈-CSDN博客 专栏:c_醋溜马桶圈的博客-CSDN博客 gitee:mnxcc (mnxcc) - Gitee.com 目录 1.面向过程和面向对象初步认识 面向过程(C语言) 面向对象(C) 2.类的引入和定义 2.1 类…

FPGA——DDR3的IP核

FPGA——DDR3的ip核 IP核配置基于MIG核代码基于AXI接口的DDR3 IP核配置 1 2 3 4 5 6 基于MIG核代码 控制MIG核的信号进行读写 module MIG_APP_Drive(input i_ui_clk ,input i_ui_rst ,input init_calib_…

Legacy|电脑Windows系统如何迁移到新安装的硬盘?系统迁移详细教程!

前言 前面讲了很多很多关于安装系统、重装系统的教程。但唯独没有讲到电脑换了新的硬盘之后,怎么把旧系统迁移到新的硬盘上。 今天小白就来跟各位小伙伴详细唠唠: 开始之前需要把系统迁移的条件准备好,意思就是在WinPE系统下,可…

AI赋能:加速MWORKS.Sysplorer仿真设计的新途径

近年来,人工智能技术的应用逐渐兴起,为仿真领域带来了新的机遇。随着现代工程系统的复杂性日益增加,MWORKS.Sysplorer作为一种广泛应用于系统仿真和设计的工具,面临着模型日益庞大和计算资源有限的挑战。为了解决这一问题&#xf…

【开发】SpringBoot 整合 Redis

目录 前言 1. Redis 的下载及安装 1.1 Redis 的下载 1.2 安装 Redis 1.3 启动 Redis 2. 创建 SpringBoot 项目整合 Redis 2.1 环境要求 2.2 SpringBoot项目构建 2.2.1 方式一 2.2.2 方式二 2.3 在 pom.xml 文件中导入依赖坐标 2.4 在 application.properties 中加…

定位线上最耗CPU的线程

定位线上最耗CPU的线程 准备工作 启动一个程序。 arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。 curl -O https://alibaba.github.io/arthas/arthas-demo.jar java -jar arthas-demo.jar[root…

组建公司办公网络

一 认识网络传输介质的分类 网络传输介质主要分为有线传输介质和无线传输介质两大类,它们在网络建设和数据传输中扮演着至关重要的角色。下面是这两类传输介质的详细分类: 有线传输介质 双绞线(Twisted Pair):这是最…

【Web】浅聊Hessian反序列化之打Spring AOP——JNDI

目录 前言 简单分析 EXP 前言 前文:【Web】浅聊Java反序列化之Rome——关于其他利用链-CSDN博客 前文里最后给到一条HotSwappableTargetSource利用链,就是我们今天PartiallyComparableAdvisorHolder链子的前半段(触发恶意类的toString方法)&#xf…

Redis中的String编码转换底层原理及6.0新特性

String编码转换底层原理 String对象为什么把大于39字节或者44字节的字符串编码为raw,小于的时候编码为embstr? 在Redis3.2以前的版本中,SDS作为字符串类型中存储字符串内容的结构,源码如下: 3.2版本SDS结构 struct sdshdr {// 记录buf数…