《JVM》第二篇 JVM内存模型深度剖析与优化

目录

      • 一. JDK体系结构与跨平台特性介绍
      • 二. JVM内存模型深度剖析
      • 三. 从Jvisualvm来研究下对象内存流转模型
      • 四. GC Root与STW机制
      • 五. JVM参数设置通用模型

一. JDK体系结构与跨平台特性介绍

在这里插入图片描述

二. JVM内存模型深度剖析

在这里插入图片描述

  1. 按照线程是否共享来划分
    在这里插入图片描述
    TLAB(Thread Local Allocation Buffer)线程本地分配缓存区,这是一个线程专用的内存分配区域
    由于对象一般会分配在上,而堆是全局共享的。因此在同一时间,可能会有多个线程在堆上申请空间。因此,每次对象分配都必须要进行同步,在竞争激烈的场合分配的效率又会进一步下降, JVM使用TLAB来避免多线程冲突,在给对象分配内存时,每个线程使用自己的TLAB,这样可以避免线程同步,提高了对象分配的效率

  2. JVM内存模型清晰版(结合代码分步解析)
    在这里插入图片描述

public class Math {private static final int INIT_DATA = 666;private static User user = new User();public int compute(){int a = 1;int b = 2;int c = (a + b) * 10;return c;}public static void main(String[] args) {Math math = new Math();int compute = math.compute();System.out.println(compute);}
}

拿Math类来解释执行步骤:
当执行Math类的main方法时,会在JVM栈内存中开辟一块内存区域,程序运行main方法,在新开辟的内存区域中开辟一块栈帧内存区域,并且压入栈底,此栈帧区域中包含许多小的内存区域;如:局部变量表,操作数栈,动态链接,方法出口… 通过每一行代码的执行来解析

  • 程序执行main方法中的Math math = new Math()
    先执行了Math类的无参构造方法,然后将Math类的静态常量至于JVM的方法区中,并且赋值,User对象存于JVM的堆内存中,方法区中存的是User对象在堆内存中的地址;initData存于方法区中,并且赋值666;
    main方法的栈帧内存区域中,开辟一块新的内存区域局部变量表,将math对象存于JVM堆内存中,并且将堆中的地址放到局部变量表中
  • 程序执行int compute = math.compute()
    在栈线程中新开辟一个compute方法的栈帧内存区域,采用后进先出的原理,compute()方法的栈帧区域在main栈帧区域上面;
    1. 执行int a = 1,先在栈帧区域中开辟一块内存区域局部变量表,将局部变量a放入,并赋初始值0,然后再将1赋值给a
    2. 执行int b = 2,将局部变量b放入局部变量表中,并赋初始值0,然后再将2赋值给b
    3. 执行int c = (a + b) * 10,开辟一个新的内存区域操作数栈,并且放入一个待操作的数10,并且从局部变量表中获取a和b的值放入操作数栈中,然后出栈执行运算,并将运算得到的结果30压入操作数栈中, 此时的操作数栈只有30一个数据
    4. 执行return c, main方法中执行math.compute()时,会在compute()方法栈帧内存区域中开辟一个新的内存区域方法出口,记录main方法中调用的位置,以便compute()方法执行完后,将结果返回到main方法中的代码执行位置

3. 总结

  • 当一个线程开始运行时,会在JVM的栈内存空间中开辟一个区域供线程运行使用
  • new出来的对象是存在堆内存空间中,栈中只存对象在堆中的位置地址
  • 方法区,记录线程中涉及的一些常量,静态变量类信息,其中对象常量或者静态变量存的都是对象在堆中的位置地址
  • 先进后出,如: 先执行的main方法,main的栈帧内存空间在线程栈的栈底,而main方法中调用的comput的栈帧区域在main的上部,从代码流程上看,调用的方法肯定是先执行完,所以后进入线程栈空间的comput栈帧,会先被GC销毁
  • 一个方法对应一个栈帧区域
  • 程序计数器:是用于存放下一条指令所在单元的地址的地方(记录当前线程执行到哪行代码了), 做标记
  • 本地方法栈: 一个线程调用Java方法或者本地方法时的栈
栈帧成员说明
局部变量表一组变量值存储空间,用于存放方法参数和方法内定义的局部变量,容量以变量槽(Variable Slot)为最小单位,一个槽可以存放一个32位的数据,局部变量表存放的都是变量在方法区中位置,JVM是通过索引定位的方式查找对应的变量
操作数栈也称操作栈,是一个后入先出栈(FILO),当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
动态链接在一个class文件中,一个方法要调用其他方法,需要将这些方法的符号引用转化为其在内存地址中的直接引用,而符号引用存在于方法区中的运行时常量池。Java虚拟机栈中,每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,持有这个引用的目的是为了支持方法调用过程中的动态连接(Dynamic Linking)。这些符号引用一部分会在类加载阶段或者第一次使用时就直接转化为直接引用,这类转化称为静态解析。
另一部分将在每次运行期间转化为直接引用,这类转化称为动态连接
方法出口有两种方式,正常完成出口,异常完成出口
①正常完成出口:指方法正常完成并退出,没有抛出任何异常,如果当前方法正常完成,则根据当前方法返回的字节码指令,这时有可能会有返回值传递给方法调用者(调用它的方法),或者无返回值。具体是否有返回值以及返回值的数据类型将根据该方法返回的字节码指令确定。
②异常完成出口:指方法执行过程中遇到异常,并且这个异常在方法体内部没有得到处理,导致方法退出。
补充说明:无论方法采用何种方式退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行。方法退出过程实际上就等同于把当前栈帧出栈,因此退出可以执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压如调用者的操作数栈中,调整PC计数器的值以指向方法调用指令后的下一条指令。

三. 从Jvisualvm来研究下对象内存流转模型

  1. 当线程执行时,会产生大量的对象,这些对象一开始会放在堆内存空间的Eden区域中,当Eden区域达到内存峰值时,会触发Minor GC进行垃圾回收,未回收的对象被称为非垃圾对象,会移到s0区域中,并且这些对象的分代年龄增加1。
  2. 当Eden区域再次达到内存峰值时,再次触发Minor GC进行垃圾回收,此时的Minor GC不仅会扫描Eden区域,而且还会扫描s0区
  3. 当Eden区域又达到内存峰值时, Minor GC会扫描Eden区域,s0和s1区域,并且将非垃圾对象移到s0区域,对象的分代年龄加1。
  4. s0和s1区域的对象会相互转移,当对象的分代年龄达到15时,会移到老年代区域中,当老年代区域达到内存峰值时,会触发Full GC,扫描整个JVM的堆内存区域和方法区,当Full GC都无法阻止老年代区域被填满,就会报OOM(内存溢出)

演示对象在堆内存各分代区域中的流转:

public class HeapTest {byte[] a = new byte[1024*100];  //100kbpublic static void main(String[] args) throws InterruptedException {List<HeapTest> heapTests = new ArrayList<>();while (true){heapTests.add(new HeapTest());Thread.sleep(10);}}
}

最后代码执行结果
在这里插入图片描述
由于HeapTests对象一直是非垃圾对象,所以GC无法回收,所以Eden、S0、S1的对象在经过一次次的GC,分代年龄一直增加,直到将老年代的内存区域撑爆,最终OOM内存溢出。

执行jvisualvm命令,打开JDK自带的监控工具
在这里插入图片描述

四. GC Root与STW机制

当执行Minor GC或者Full GC时,会执行STW(停止整个事件),停止用户所有线程,GC执行完,再恢复。

  1. ★GC过程中为什么会执行STW机制?
    因为如果不执行STW,一边进行GC,一边线程继续执行,那么当线程执行完时,会进行
    出栈操作,所有在栈中开辟的内存区域全部释放,而GC无法处理的非垃圾对象此时没
    有引用,而会被GC当作垃圾对象清理,在现实的生产环境中,这显然是不允许的。

  2. JVM优化,就是减少Full GC和Minor GC的次数
    尽可能让对象都在新生代里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁的进行垃圾回收。

五. JVM参数设置通用模型

在这里插入图片描述

  1. Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):
    java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar microservice‐eurek a‐server.jar

  2. 关于元空间的JVM参数有两个:-XX:MetaspaceSize=N-XX:MaxMetaspaceSize=N
    -XX:MaxMetaspaceSize:设置元空间最大值,默认是-1,即不限制,或者说只受限于
    本地内存大小。
    -XX:MetaspaceSize:指定元空间触发Full GC的初始阈值(元空间无固定初始大小),
    以字节为单位,默认是21M,达到该值就会触发Full GC进行类型卸载

  3. 同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;
    如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize(如果设置了的话)的情况下,适当提高该值。这个跟早期JDK版本的-XX:PermSize(代表永久代的初始容量)参数意思不一样,

  4. 由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候
    发生大量Full GC,通常都是由于永久代或元空间发生了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大,对于8G物理内存的机器来说,一般会将这两个值都设置为256M

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

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

相关文章

【JAVA】关于抽象类的概念

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 前言 在Java中&#xff0c;抽象类是一种特殊的类&#xff0c;它无法被实例化。它只能被用作其他类的基类&#xff0c;以便子类可以继承它的属性和方法。今天我们就来谈谈JAVA中的抽象类。…

使用 ggbreak 包进行Y轴多次截断

简介 最近在科研中需要比较不同模型的预测性能&#xff0c;我们使用相对偏差&#xff0c;均方根误差等来比较结果。此时&#xff0c;可能会得到以下结果&#xff1a; 上图出现以下问题&#xff1a; 问题一&#xff1a;由于经典模型&#xff08;Normal&#xff09;在复杂数据中…

优化系统报错提示信息,提高人机交互(二)

如果服务器接口报错&#xff0c;接口返回报错信息&#xff0c;是怎么实现的呢&#xff1f; 接口调用示例 controller代码 AllArgsConstructor RestController Slf4j public class DemoController {GetMapping("exceptionTest")public Result exceptionTest(Integer…

[linux(静态文件服务)] 部署vue发布后的dist网页到nginx

所以说&#xff1a; 1.windows下把开发好的vue工程打包为dist文件然后配置下nginx目录即可。 2.linux上不需要安装node.js环境。 3.这样子默认访问服务器ip地址&#xff0c;就可以打开&#xff0c;毕竟默认就是&#xff1a;80端口。

STL常用遍历,查找,算法

目录 1.遍历算法 1.1for_earch 1.2transform 2.常用查找算法 2.1find&#xff0c;返回值是迭代器 2.1.1查找内置数据类型 2.1.2查找自定义数据类型 2.2fin_if 按条件查找元素 2.2.1查找内置的数据类型 2.2.2查找内置数据类型 2.3查找相邻元素adjeacent_find 2.4查找指…

【子平真诠】擂台赛中的一个癸生子月的坤造

这期擂台赛的一个盘&#xff0c;建禄格&#xff0c;为什么特地拿出来写一期&#xff0c;一是因为我这两天更懒了&#xff0c;想玩&#xff0c;闲的。二是经常会遇到建禄格&#xff0c;月劫格的人&#xff0c;挺难断的这种盘。三是同为癸亥。 晚上才出结果&#xff0c;我现在速成…

Spring面试题5:面试官:为什么说Spring是一个容器?如何给Spring容器提供配置元数据?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:为什么说Spring是一个容器? Spring被称为一个容器,是因为它提供了一个运行环境和管理机制,用于管理应用程序中的对象的生命周期和依赖关系。 …

通过插件去除Kotlin混淆去除 @Metadata标记

在Kotlin中&#xff0c;Metadata是指描述Kotlin类的元数据。它包含了关于类的属性、函数、注解和其他信息的描述。Metadata的作用主要有以下几个方面&#xff1a; 反射&#xff1a;Metadata可以用于在运行时获取类的信息&#xff0c;包括类的名称、属性、函数等。通过反射&…

两分钟搞懂什么是反向代理与正向代理

正向代理&#xff08;Forward Proxy&#xff09;和反向代理&#xff08;Reverse Proxy&#xff09;都是常见的代理服务器类型&#xff0c;它们在网络通信中起到不同的作用。 正向代理&#xff1a; 正向代理是位于客户端和目标服务器之间的代理服务器。当客户端想要访问目标服务…

融云观察:AI Agent 是不是游戏赛道的下一个「赛点」?

本周四 融云直播间&#xff0c;点击报名~ ChatGPT 的出现&#xff0c;不仅让会话成为了未来商业的基本形态&#xff0c;也把大家谈论 AI 的语境从科技产业转向了 AI 与全产业的整合。 关注【融云全球互联网通信云】了解更多 而目前最热衷于拥抱生成式 AI 的行业中&#xff0c…

【深度学习实验】线性模型(一):使用NumPy实现简单线性模型:搭建、构造损失函数、计算损失值

#【中秋征文】程序人生&#xff0c;中秋共享# 目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入库 1. 定义线性模型linear_model 2. 定义损失函数loss_function 3. 定义数据 4. 调用函数 一、实验介绍 使用Numpy实现 线性模型搭…

clickhouse简单安装部署

目录 前言(来源于官方文档)&#xff1a; 一.下载并上传 1.下载地址&#xff1a;点我跳转下载 2.上传至Linux 二.解压和配置 1.解压顺序 注意&#xff1a;必须按照以下顺序解压&#xff0c;并且每解压一个都要执行该解压后文件的install/doinst.sh文件 解压步骤&#xff…

如何安全传输存储用户密码?(程序员必备)

前言 我们开发网站或者APP的时候&#xff0c;首先要解决的问题&#xff0c;就是「如何安全传输和存储用户的密码」。一些大公司的用户数据库泄露事件也时有发生&#xff0c;带来非常大的负面影响。因此&#xff0c;如何安全传输存储用户密码&#xff0c;是每位程序员必备的基础…

寻找单身狗

在一个数组中仅出现一次&#xff0c;其他数均出现两次&#xff0c;这个出现一次的数就被称为“单身狗“。 一.一个单身狗 我们知道异或运算操作符 ^ &#xff0c;它的特点是对应二进制位相同为 0&#xff0c;相异为 1。 由此我们容易知道两个相同的数,进行异或运算得到的结果…

提示计算机丢失msvcp140.dll怎么办,缺少msvcp140.dll一键修复

在计算机使用过程中&#xff0c;我们可能会遇到各种稀奇古怪的问题。其中&#xff0c;msvcp140.dll 文件丢失算是比较常见的一种。那么&#xff0c;究竟什么是 msvcp140.dll 文件&#xff1f;它为什么会丢失&#xff1f;我们又该如何解决这个问题呢&#xff1f;本文将围绕这些问…

高性能计算环境下的深度学习异构集群建设与优化实践

★深度学习&#xff1b;模式识别&#xff1b;图像处理&#xff1b;人工智能建模&#xff1b;人工智能&#xff1b;深度学习算法&#xff1b;强化学习&#xff1b;神经网络&#xff1b;卷积神经网络&#xff1b;人工神经网络&#xff1b;VIBE算法&#xff1b;控制系统仿真&#…

1 MySQL 高级(进阶) SQL 语句(一)

目录 1 MySQL SQL 语句 1.1SELECT 1.2 DISTINCT 1.3 WHERE 1.4 AND OR 1.5 in 1.6 BETWEEN 2 通配符 ----通常通配符都是跟 LIKE 一起使用的 2.1 LIKE 2.2 ORDER BY 3函数 3.1数学函数 3.2 聚合函数 3.3 字符串函数 4 GROUP BY 4.1 HAVING 5 别名 6 子查询 …

NSS [HXPCTF 2021]includer‘s revenge

NSS [HXPCTF 2021]includer’s revenge 题目描述&#xff1a;Just sitting here and waiting for PHP 8.1 (lolphp). 题目源码&#xff1a;&#xff08;index.php&#xff09; <?php ($_GET[action] ?? read ) read ? readfile($_GET[file] ?? index.php) : inclu…

数字孪生在灌区信息中的应用

灌区信息是智慧水利的组成部分&#xff0c;对灌区现代化改造的支撑作用和地位尤为重要&#xff0c;对促进水利可持续发展有重要意义。灌区信息化系统主要对对灌区的水情、雨情、土壤墒情、气象等信息进行监测&#xff0c;对重点区域进行视频监控&#xff0c;同时对泵站、闸门进…

服务器搭建(TCP套接字)-fork版(服务端)

基础版的服务端虽然基本实现了服务器的基本功能&#xff0c;但是如果客户端的并发量比较大的话&#xff0c;服务端的压力和性能就会大打折扣,为了提升服务端的并发性能&#xff0c;可以通过fork子进程的方式&#xff0c;为每一个连接成功的客户端fork一个子进程&#xff0c;这样…