java JVM详解(持续更新)

JVM定义

JVM结构

类装载子系统

双亲委派模型

运行时数据区

方法区(Method Area)

堆区(Heap)

虚拟机栈区

程序计数区

执行引擎子系统

垃圾回收机制

内存分代机制

JVM调优

JVM面试题

JVM定义

JVM它是jre的一部分,也java程序最终运行的地方。jdk默认虚拟机HotSpot。

我们编写的java代码,编译后会生成对应的.class文件,这个文件是字节码文件,紧接着JVM 通过类装载子系统将字节码文件装载到运行时数据区,该区域将字节码内容拆分分别装载到JVM运行时数据区的方法区、堆、栈、本地方法栈和程序计数器 几个部分,最终送到执行引擎子系统配合本地接口然后运行。

JVM结构

JVM由两个子系统和两个组件构成。

子系统:

子系统 内容
类装载子系统(ClassLoader)根据给定的全限定类名称装载class文件到运行时数据区的方法区
执行引擎子系统(Execution engine)包含即时编译器(JITCompiler)和垃圾回收器(Garbage Collector);用于执行class文件中的命令

组件:

组件内容
运行时数据区(Runtime data Area)jvm的内存,包含方法区、虚拟机栈、本地方法栈、堆、程序计数器
本地接口(Native Interface)与本地方法库交互,与其他变成语言交互的接口

在这里插入图片描述

类装载子系统

类的加载是通过双亲委派模型来完成的

类的生命周期:加载、验证、准备、解析、初始化、使用、卸载

双亲委派模型

加载器找到.class文件找到并读取,双亲委派模型描述的是加载器找到.class文件得基本过程。

即加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器. 父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载.

运行时数据区

JVM在执行Java程序时,会把它管理的内存划分为若干个的区域,每个区域都有自己的用途和创建销毁时间。

区域线程属性内存占比
堆区共享 最大
虚拟机栈私有
方法区共享
程序计数器私有较小

在这里插入图片描述

方法区(Method Area)

线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

例如,在程序中声明的常量、静态变量和有关于类的信息等的引用,都会存放在方法区,而这些引用所指向的具体对象 一般都会在堆中开辟单独的空间进行存储,也可能会在直接内存中进行存储。

在这里插入图片描述

堆区(Heap)

通过new关键字创建的对象都会被放在堆内存,由于堆是线程共享的,所以堆内存中的对象都需要考虑线程安全问题。

堆中的数据不需要事先明确生存期,可以动态的分配内存,不再使用的数据和对象由JVM中的GC机制自动回收。对JVM的性能调优一般就是对堆内存的调优。

Java中基本类型的包装类:Byte、Short、Integer、Long、Float、Double、Boolean、Character类型的数据是存储在堆中的。

堆区内存分为两个不同区域:新生代(Young)和老年代(Old)。
年轻代又会被进一步分为1个Eden区和2个Survivor区。在内存分配上,如果保持默认配置的话,年轻代和老年代的内存大小比例为1 : 2,年轻代中的1个Eden区和2个Survivor区的内存大小比例为:8 : 1 : 1。

在这里插入图片描述

虚拟机栈区

每个线程运行需要的内存空间,用于保存方法执行的内存模型。
每个栈由多个栈帧(Frame)组成,对应着每次调用方法时所占用的内存。
每个线程只能有一个活动栈帧,对应着当前正在执行的方法

程序计数区

用于保存当前线程所正在执行的字节码指令的地址(行号)

执行引擎子系统

垃圾回收机制

  1. 目的

    程序运行过程中会产生大量的内存垃圾,为了确保程序运行时的性能,JVM会在过程中不断地进行自动垃圾回收

  2. 关注对象

    程序计数器、虚拟机栈、本地方法栈是线程私有的,所以会随着线程结束而消亡。
    Java 堆和方法区是线程共享的,在程序处于运行期才知道哪些对象会创建,这部分内存的分配和回收都是动态的,垃圾回收所关注的就是这部分内存。

  3. 判断对象可以回收

    在进行内存回收之前要做的事情就是判断那些对象是‘死’的,哪些是‘活’的

    • 引用计数法:当一个对象被引用时,就当引用对象的值加一,当值为 0 时,就表示该对象不被引用,可以被垃圾收集器回收。
    • 可达性分析

  4. 垃圾回收算法

    算法速度碎片空间
    标记清除算法 较快产生内存碎片
    标记整理算法没有内存碎片
    复制算法没有内存碎片占用两倍内存空间
    分代垃圾回收算法

内存分代机制

方法区即被称为永久代,而堆中存放的是对象实例,为了回收的时候对不同的对象采用不同的方法,又将堆分为新生代和老年代,默认情况下新生代占堆的1/3,老年代占堆的2/3。

• 新生代(Young):HotSpot将新生代划分为三块,一块较大的Eden空间和两块较小的Survivor空间,默认比例为8:1:1。
• 老年代(Old):在新生代中经历了多次GC后仍然存活下来的对象会进入老年代中。老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢。
• 永久代(Permanent):永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,一般而言不会进行垃圾回收。
• 元空间(metaspace):从JDK 8开始,Java开始使用元空间取代永久代,元空间并不在虚拟机中,而是直接使用本地内存。那么,默认情况下,元空间的大小仅受本地内存限制。当然,也可以对元空间的大小手动的配置。

JVM调优

  1. JDK自带工具

    JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是jconsole和jvisualvm这两款视图监控工具。

    • jconsole:用于对JVM中的内存、线程和类等进行监控;
    • jvisualvm:JDK自带的全能分析工具,可以分析:内存快照、线程快照、程序 死锁、监控内存的变化、gc变化等。

  2. 第三方工具

    • MAT(MemoryAnalyzer Tool):基于Eclipse的内存分析工具
    • GChisto:专业分析gc日志的工具

  3. 调优参数

    -Xms2g:初始化推大小为2g
    -Xmx2g:堆最大内存为2g (为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,通常把最大、最小设置为相同的值)
    -XX:NewSize=m;设置年轻代大小
    -XX:NewRatio=4:设置年轻代的和老年代的内存比例为 1:4; 年轻代和年老代将根据默认的比例(1:2)分配堆内存.
    -XX:SurvivorRatio=8:设置新生代Eden和Survivor比例为 8:1

在这里插入图片描述

在JVM中,主要是对堆(新生代)、方法区和栈进行性能调优。各个区域的调优参数如下所示。

• 堆:-Xms、-Xmx
• 新生代:-Xmn
• 方法区(元空间):-XX:MetaspaceSize、-XX:MaxMetaspaceSize
• 栈(线程):-Xss

为了更加直观的表述,我们可以将JVM的内存区域和对应的调优参数总结成下图所示。

在这里插入图片描述
在设置JVM启动参数时,需要特别注意方法区(元空间)的参数设置。

关于方法区(元空间)的JVM参数主要有两个:-XX:MetaspaceSize和-XX:MaxMetaspaceSize。

-XX:MetaspaceSize:指的是方法区(元空间)触发Full GC的初始内存大小(方法区没有固定的初始内存大小),以字节为单位,默认为21M。达到设置的值时,会触发Full GC,同时垃圾收集器会对这个值进行修改。

如果在发生Full GC时,回收了大量内存空间,则垃圾收集器会适当降低此值的大小;如果在发生Full GC时,释放的空间比较少,则在不超过设置的-XX:MetaspaceSize值或者在没设置-XX:MetaspaceSize的值时不超过21M,适当提高此值。

-XX:MaxMetaspaceSize:指的是方法区(元空间)的最大值,默认值为-1,不受堆内存大小限制,此时,只会受限于本地内存大小。

最后需要注意的是:调整方法区(元空间)的大小会发生Full GC,这种操作的代价是非常昂贵的。如果发现应用在启动的时候发生了Full GC,则很有可能是方法区(元空间)的大小被动态调整了。

所以,为了尽量不让JVM动态调整方法区(元空间)的大小造成频繁的Full GC,一般将-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置成一样的值。例如,物理内存8G,可以将这两个值设置为256M

最后,我们一起看下在物理内存8G的情况下,启动应用程序时,可以设置的JVM参数。当然,我这里给出的是一些经验值,实际部署到生产环境时,需要经过压测找到最佳的参数值。

• 启动SpringBoot:
  java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar xxx.jar

• 启动Tomcat(Linux):
  在Tomcat bin目录下catalina.sh文件里配置。
  ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

• 启动Tomcat(Windows)
  在Tomcat bin目录下catalina.bat文件里配置。
  ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

JVM面试题

  1. 垃圾回收是否涉及栈内存?

    不会。栈内存是方法调用产生的,方法调用结束后会弹出栈。

  2. 栈内存分配越大越好吗?

    物理内存是一定的,栈内存越大,可以支持更多的递归调用,但是可执行的线程数就会越少。

  3. 栈内存溢出的原因

    栈帧过大、过多、或者第三方类库操作,都有可能造成栈内存溢出 java.lang.stackOverflowError,使用 -Xss256k 指定栈内存大小

  4. 堆内存调整参数

    可以使用 -Xmx8m 来指定堆内存大小。

  5. 堆内存诊断方法

    jps -》查看当前系统中有哪些 java 进程
    jmap -》查看堆内存占用情况 jmap - heap 进程id

  6. Java中创建的对象是存储在JVM中的哪个区域的?

    例如,这里,我们简单的列举一行代码,如下所示。

    User user = new User();
    

    关于上面的代码,不少小伙伴都知道,创建出来的User对象是放在JVM中的堆区域的,而User对象的引用是放在栈中的。但如果你只是了解到这种程度,那面试官就会认为你了解的太浅显了,可能就会达不到他们的要求。其实面试官想要了解你是否对JVM有一个更深入的认识。

    站在面试官的角度来看这个问题时,回答创建出来的User对象是放在JVM的堆区,也并没有错。但是JVM的堆内存区域又会分为年轻代和老年代,而年轻代又会分为Eden区和Survivor区。JVM堆空间的逻辑结构如下图所示。

    在这里插入图片描述
    而面试官更想了解的是你能不能说出来创建的对象具体是存放在JVM堆空间的哪个区域。

    在JVM内部,会将整个堆空间划分成年轻代和老年代,年轻代默认会占整个堆内存空间的1/3,老年代默认会占整个堆内存空间的2/3。年轻代又会划分为Eden区和两个Survivor区,它们之间的默认比例是Eden:Survivor1:Survivor2 = 8:1:1。

在这里插入图片描述

如果你能回答出 新创建的User对象是存放在JVM堆空间中年轻代的Eden区,那面试官就会对你刮目相看了。当然,这里没有考虑JVM的逃逸分析情况

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

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

相关文章

sentinel使用控制台实现

1、添加依赖 <!--整合控制台--><dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.0</version></dependency> 此项方法&#xff0…

PSO-ELM,粒子群优化算法优化ELM极限学习机数据回归预测(多输入单输出)-MATLAB实现

粒子群优化算法&#xff08;Particle Swarm Optimization, PSO&#xff09;结合极限学习机&#xff08;Extreme Learning Machine, ELM&#xff09;进行数据回归预测是一种常见的机器学习方法。ELM作为一种单隐层前馈神经网络&#xff0c;具有快速训练和良好的泛化能力。而PSO则…

报表生成器FastReport .Net用户指南:关于脚本(下)

FastReport的报表生成器&#xff08;无论VCL平台还是.NET平台&#xff09;&#xff0c;跨平台的多语言脚本引擎FastScript&#xff0c;桌面OLAP FastCube&#xff0c;如今都被世界各地的开发者所认可&#xff0c;这些名字被等价于“速度”、“可靠”和“品质”,在美国&#xff…

【CKA模拟题】查找集群中使用内存最高的node节点

题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetesFind the Node that consumes the most MEMORY in all cluster(currently we have single cluster). Then, store the result in the …

MySQL数据库的下载和安装以及命令行语法学习

MySQL数据库的下载和安装以及命令行语法学习 学习MYSQL&#xff0c;掌握住基础的SQL句型&#xff08;创建数据库、查看数据库列表、数据增、删、改、查等操作类型&#xff09; 首先要知道MySQL下载和安装方法&#xff1a; 提示&#xff1a;别嫌啰嗦&#xff0c;对于一个初识MY…

python智慧农业小程序flask-django-php-nodejs

当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#xff0c;国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统智慧农业采取了人工的管理方法&#xff0c;但这…

基于Python3的数据结构与算法 - 16 链表

目录 链表 1. 创建链表 2. 链表的插入和删除 3. 双链表 4. 链表总结 链表 链表是由一系列节点组成的元素集合。每个节点包含两部分&#xff0c;数据域item和指向下一个节点得指针next。通过节点之间的相互连接&#xff0c;最终串联成一个链表。 class Node:def __init…

vue key的bug

今天遇到一个bug&#xff0c;列表删除元素时&#xff0c;明明在外层设置了key&#xff0c;但是列表元素的状态居然复用了&#xff0c;找了好久原因&#xff0c;最后是key的取值问题&#xff0c;记录一下。 首先key可以取undefine&#xff0c;这个是不会报错的 然后项目的代码结…

通过 Socket 手动实现 HTTP 协议

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

社交媒体的未来:探讨Facebook的发展趋势

引言 在数字化时代&#xff0c;社交媒体已经成为人们日常生活中不可或缺的一部分。作为全球最大的社交媒体平台之一&#xff0c;Facebook一直在不断地追求创新&#xff0c;以满足用户日益增长的需求和适应科技发展的变革。本文将探讨Facebook在未来发展中可能面临的挑战和应对…

WM8978 —— 带扬声器驱动程序的立体声编解码器(2)

接前一篇文章&#xff1a;WM8978 —— 带扬声器驱动程序的立体声编解码器&#xff08;1&#xff09; 六、引脚详细说明 引脚&#xff08;PIN&#xff09;名称&#xff08;NAME&#xff09;类型&#xff08;TYPE&#xff09;描述&#xff08;DESCRIPTION&#xff09;1LIP模拟输入…

uniApp中使用小程序XR-Frame创建3D场景(1)环境搭建

1.XR-Frame简介 XR-Frame作为微信小程序官方推出的3D框架&#xff0c;是目前所有小程序平台中3D效果最好的一个&#xff0c;由于其本身针对微信小程序做了优化&#xff0c;在性能方面比其他第三方库都要高很多。 2.与Three.js的区别 做3D小程序的同学们对Three.js一定不陌生…

停止docker 容器并删除对应镜像

docker 容器相关命令 docker ps 查看当前系统正在运行的容器情况&#xff0c;返回信息分别为&#xff1a; 容器ID&#xff1a;CONTAINER ID 镜像名IMAGE NAMES 运行命令COMMAND 创建时间CREATED 状态STATUS 映射端口 PORTS docker ps |grep XXX 可以…

ssm项目(tomcat项目),定时任务(每天运行一次)相同时间多次重复运行job 的bug

目录标题 一、原因 一、原因 debug本地调试没有出现定时任务多次运行的bug&#xff0c;上传到服务器就出现多次运行的bug。&#xff08;war的方式部署到tomcat&#xff09; 一开始我以为是代码原因&#xff0c;或者是linux和win环境不同运行定时任务的方式不一样。 但是自己…

sentinel整合gateway实现服务限流

导入依赖: <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.csp</groupId><…

数据结构:堆的创建和使用

上一期我们学习了树和二叉树的定义&#xff0c;其中我们了解到了两种特殊的二叉树&#xff1a;满二叉树和完全二叉树。 今天我们还要学习一种新的结构&#xff1a;堆 那这种结构和二叉树有什么联系呢&#xff1f;&#xff1f;&#xff1f; 通过观察我们可以发现&#xff0c;…

UE5 C++增强输入

一.创建charactor&#xff0c;并且包含增强输入相关的头文件 1.项目名.build.cs。添加模块“EnhancedInput”&#xff0c;方便找到头文件和映射的一些文件。 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine&q…

塔楼VR火灾逃生应急安全教育突破了传统模式

城镇化的高速发展&#xff0c;给消防安全带来了严峻的挑战&#xff0c;尤其是人员密集的办公场所&#xff0c;如何预防火灾发生&#xff0c;学习火灾成因&#xff0c;减少火灾发生避免不必要的损失&#xff0c;成为安全应急科普的重中之重。 通过模拟真实的办公场所火灾场景&am…

中国贸易金融跨行交易区块链平台CTFU、区块链福费廷交易平台BCFT、中国人民银行贸易金融区块链平台CTFP、银行函证区块链服务平台BPBC

中国人民银行贸易金融区块链平台CTFP介绍 贸易金融的发展概况及存在的问题 1.1 贸易金融的概况 贸易金融是指商业银行在贸易双方债权债务关系的基础上&#xff0c;为国内或跨国的商品和服务贸易提供的贯穿贸易活动整个价值链、全程全面性的综合金融服务。伴随全球化的进程&a…

【Mock|JS】Mock的get传参+获取参数信息

mockjs的get传参 前端请求 const { data } await axios("/video/childcomments", {params: {sort: 1,start: 2,count: 5,childCount: 6,commenIndex: 0,},});后端获取参数 使用正则匹配url /*** # 根据url获取query参数* param {Url} urlStr get请求获取参数 eg:…