JVM的原理与性能

1 JVM 内存结构

在这里插入图片描述

1.1 运行时数据区

1.1.1 栈(虚拟机栈)

每个线程在创建时都会创建一个私有的Java虚拟机栈,在执行每个方法时都会打包成一个栈帧,存储了局部变量表操作数栈动态链接方法出口等信息,然后放入栈中。方法的执行对应着栈帧出栈的过程。栈的大小默认为1M,可通过参数-Xss调整大小,如-Xss256k。

1.1.2 本地方法栈

与虚拟机栈类似,只是对应的是本地方法

1.1.3 程序计数器

程序计数器用于记录当前线程所执行的字节码指令的行号。

1.1.4 方法区

用于存储已经被虚拟机加载的类信息、常量、静态变量等数据。可通过参数(JDK1.8以后)-XX:MetaspaceSize, -XX:MaxMetaspaceSize调节,如-XX:MaxMetaspaceSize=3M。

1.1.5 堆

堆是Java中最大的一部分,它用于存储对象实例。所有的对象实例以及数组都在堆上分配内存。堆是由垃圾回收器自动管理的,因此开发者不需要关心内存的回收问题。但是,由于垃圾回收器的存在,堆上的数据可能会影响程序的性能。
可通过以下参数调节:-Xms:堆的最小值;-Xmx:堆的最大值;-Xmn:新生代的大小;-XX:NewSize:新生代最小值;-XX:MaxNewSize:新生代最大值;例如-Xmx256m堆划分为新生代和老年代,新生代又分为Eden区、Survivor1(from)区、Survivor2(to)区。

1.2 直接内存

调用native函数直接分配的堆外内存,使用直接内存避免了JAVA堆与native堆来回复制数据,能够提高效率。默认与-Xmx 参数值相同为 100M。可以通过-XX:MaxDirectMemorySize 来单独设置直接内存的大小。

1.3 Java的垃圾回收(Garbage Collection)机制

Java的垃圾回收是JVM自动回收不再使用的对象所占用的内存的过程。它减少了开发者手动管理内存的负担,避免了内存泄漏的问题。

垃圾回收器通过跟踪每个对象的引用关系来决定哪些对象是可达的,哪些对象是不可达的。当一个对象没有任何引用指向它时,它就被认为是不可达的,因此可以被垃圾回收器回收。

垃圾回收器的工作过程大致如下:

  • 从根对象(Root Object)开始遍历整个堆内存,标记所有被引用的对象;
  • 遍历整个堆内存,找到没有被标记的对象,将其回收;
  • 更新堆的大小。

在执行垃圾回收时,JVM会将所有线程暂停一段时间,这个过程被称为“Stop-The-World”。这可能会对程序的性能产生影响,因此优化垃圾回收器的性能是提高JVM性能的一个重要方向。

1.4 垃圾回收算法

1.4.1 标记-清除

首先标记所有需要回收的对象,在标记完成后,统一回收掉所有标记的对象(也可以标记存活对象,回收未标记的对象)。 缺点:执行效率不稳定(随着对象数量增长而降低)、内存空间碎片化。

1.4.2 标记-复制(简称复制算法)

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存用完了,就将还存活的对象复制到另一块,然后再把已使用过的内存空间一次清理掉。

缺点:内存缩小为原来的一半。

商用虚拟机大多采用这种算法回收新生代,大多数对象是朝生夕死的(约98%对象熬不过第一轮收集),因此并不需要按照1:1来划分新生代的内存空间。

Appel式回收将新生代划分为一块较大的Eden区和两块较小的Survivor区,每次分配内存只使用Eden区和其中一块Survivor区, 发生垃圾回收时,将Eden区和Survivor区中仍然存活的对象一次性复制到另外一块Survivor区上,然后清理掉Eden区和使用过的Survivor区。HotSpot虚拟机默认Eden和Survivor的大小比例为8:1,只有一个Survivor空间,即10%的新生代会被浪费。任何时候都没法保证每次回收后只有少于10%的对象存活,当Suvivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(大多是老年代)进行分配担保。

1.4.3 标记-整理

标记-复制算法在对象存活率较高时要进行较多的复制操作,效率会降低。如果不想浪费50%的空间,就需要额外的空间进行分配担保,所以老年代不直接使用标记-复制算法。

标记-整理算法的标记过程与标记-清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象向内存空间的一端移动,然后清理掉边界以外的内容。

移动存活对象并更新所以引用这些对象的地方是一个极为负重的操作,必须全程暂停用户程序(称为Stop The World)才能进行。

1. 5 类加载的过程

1.5.1 加载

加载阶段,虚拟机需要完成三件事:

  • **获取类的二进制流:**通过类的全限定名获取类的二进制字节流。
  • 转化成运行时数据结构 将字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 生成类对象: 在内存中生产一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。

1.5.2 验证

是连接的第一步,目的是确保Class文件的字节流中包含的信息符合**《JAVA 虚拟机规范》**的全部约束,保证这些信息被当做代码运行后不会危害虚拟机自身的安全。 大致需要完成四个阶段的检验动作: 文件格式验证 验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。验证包括:魔数、主次版本号、常量池等等。 元数据验证 对字节码描述的信息进行语义分析,以保证其描述的信息符合《JAVA 语言规范》的要求。验证包括:类是否有父类、类是否继承了不允许被继承的类、类的字段和方法是否与其父类产生矛盾等。 字节码验证 通过数据流分析和控制流分析,确定程序的语义是合法的、符合逻辑的。 符号引用验证 验证符号引用全限定名代表的类是否能够找到,对应的域和方法是否能找到,访问权限是否合法。

1.5.3 准备

为类中定义的类变量(被static修饰的变量)分配内存并设置初始值。通常情况下初始化是零值,只有变量被final修饰时,才会初始化为指定的值。

1.5.4 解析

将常量池中的符号引用替换为直接引用的过程。

1.5.5 初始化

根据程序员编码制订的主观计划区初始化类变量和其他资源。

1.6 类加载器

对于任意一个类,都必须由加载它的类加载器和这个类本身来确定其在JAVA虚拟机中的唯一性。每一个类加载器都都拥有一个独立的类名称空间。

主要有四种类加载器:

  • 启动类加载器(Bootstrap ClassLoader): 用来加载JAVA 核心库(JAVA_HOME\lib目录下)。

  • 扩展类加载器(Extension ClassLoader): 用来加载JAVA扩展库(JAVA_HOME\lib\ext目录下)。

  • 应用类加载器(Application ClassLoader,也称系统类加载器): 负责加载用户类路径(ClassPath)上的所有类库。可通过ClassLoader.getSystemClassLoader()来获取。如果应用中没有自定义的类加载器,一般情况下为应用程序中的默认类加载器。

  • 自定义类加载器(User ClassLoader): 通过继承java.lang.ClassLoader类实现。

1.7 双亲委派模式

如果一个类加载器接收到了加载类的请求,它首先不会去自己加载这个类,而是委托给父类加载器加载,依次递归。只有当父类加载器不能完成加载任务时,自己才去加载。 双亲委派模式的好处:JAVA中的类随着它的类加载器一起具备了一种带有优先级的层次关系。例如,java.lang.Object类,无论哪个类加载器加载,最终都会委托给最顶层的启动类加载器加载,因此Object类在程序的各种类加载器环境中都能保证是同一个类。

Tomcat打破双亲委派模型。

1.8 JVM性能优化

1.8.1 内存溢出

程序在申请内存时,没有足够的空间。情况如下:

  • 栈溢出。 循环调用(StackOverflowError)、线程太多(OutOfMemoryError)。

  • 堆溢出。 不断创建对象,分配大对象堆内存。

  • 方法区溢出。在经常动态生产大量 Class 的应用中,CGLIb 字节码增强,动态语言,大量 JSP(JSP 第一次运行需要编译成 Java 类),基于 OSGi 的应用(同一个类,被不同的加载器加载也会设为不同的类)。

  • 直接内存溢出。可以通过-XX:MaxDirectMemorySize来设置。

1.8.2 内存泄露

程序在申请内存后,无法释放已申请的内存。 可能存在内存泄露的情况:

  • 长生命周期的对象持有短生命周期的对象。如将ArrayList设置为静态变量,则容器中的对象在程序结束之前将不能被释放。

  • 连接未关闭。如数据库连接、网络连接、IO连接等。 变量作用作用域不合理 一个变量定义的作用范围大于其使用范围,并没有及时设置为null。

  • 内部类持有外部类。Java 的非静态内部类的这种创建方式,会隐式地持有外部类的引用,而且默认情况下这个引用是强引用,因此,如果内部类的生命周期长于外部类的生命周期,程序很容易就产生内存泄漏。

  • Hash值改变。在集合中,如果修改了对象中的那些参与计算哈希值的字段,会导致无法从集合中单独删除当前对象,造成内存泄露。

1.8.3 JVM 参数配置

-Xmx3550m: 最大堆大小为 3550m。
-Xms3550m: 设置初始堆大小为 3550m。
-Xmn2g: 设置年轻代大小为 2g。
-Xss128k: 每个线程✁堆栈大小为 128k。
-XX:MaxPermSize: 设置持久代大小为 16m
-XX:NewRatio=4: 设置年轻代(包括Eden 和两个Survivor 区)与年老代
的比值(除去持久代)。
-XX:SurvivorRatio=4: 设置年轻代中Eden 区与 Survivor 区的大小比值。
设置为 4,则两个 Survivor 区与一个 Eden 区✁比值为 2:4,一个 Survivor区占整个年轻代的 1/6
-XX:MaxTenuringThreshold=0: 设置垃圾最大年龄。如果设置为 0
的话,则年轻代对象不经过 Survivor 区,直接进入年老代。

1.8.4 JDK提供的优化工具

    命令行工具:

    jps

    列出当前机器上正在运行的虚拟机进程。

    jps 显示进程和启动类名称

    jps –q 只显示进程

    jps –m 输出主函数传入的参数

    jps –l 输入主函数完整包名

    jps –v 输入启动程序制定的jvm参数

    jstat

    用于监视虚拟机各种运行信息的命令行工具。显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT(即时编译)等运行数据。

    用法:jstat –xx 进程号

    jstat –class 类加

    jstat –compiler JIT

    jstat –gc  GC堆状态

    jstat –gccapacity 各区大小

    jstat –gccause 最近一次gc统计和原因

    jstat –gcnew 新生代统 

    jstat –gcnewcapacity 新生代大小

    jstat –gcold 老年代统计

    jstat –gcoldcapacity 老年代大小

    jstat –gcpermcapacity 永久代大小

    jstat –gcutil gc统计汇总

    jstat –printcompilation 虚拟机编译统计

    jinfo

    查看和修改虚拟机参数

    用法:jinfo [option] <pid>

    jinfo –sysprops 获取虚拟机参数,等价于System.getProperties()

     jinfo –flag <name> 输出对应名称的参数

    jinfo –flag [+|-]<name> 开启或关闭对应名称的参数

    jinfo –flags 输出所有的参数

    jmap

    用于查看堆和永久代的详细信息、生成堆转储快照(dump文件)

    用法:jmap [option] <pid>

    jmap –heap 查看堆

    jmap –finalizerinfo查询 finalize 执行队列

    jmap –dump 导出堆dump文件 例如:jmap –dump:live –format=b,file=D:\heap.bin 1740

    jhat

    生成dump文件分析,可在浏览器上访问:http://localhost:7000

    jhat <dump文件>

    jstack

    查看虚拟机线程信息。

    可视化工具:

    jconsole

    JAVA_HOME\bin\jconsole.exe

    jvisualvm

    JAVA_HOME\bin\jvisualvm.exe

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实现echarts地图

效果图: 2.echarts.registerMap("xizang", XZ) 注册了一个名为 "xizang" 的地图&#xff0c;其中 XZ 是地图数据。 接下来是 option 对象&#xff0c;包含了图表的配置信息&#xff0c;比如图表的布局、提示框样式、地理组件配置和系列数据配置等。 在 t…

Day 28 MySQL的数据备份与恢复

数据备份及恢复 1.概述 ​ 所有备份数据都应放在非数据库本地&#xff0c;而且建议有多份副本 备份&#xff1a; 能够防止由于机械故障以及人为误操作带来的数据丢失&#xff0c;例如将数据库文件保存在了其它地方 冗余&#xff1a; 数据有多份冗余&#xff0c;但不等备份&…

vivado Virtex-7 配置存储器器件

Virtex-7 配置存储器器件 下表所示闪存器件支持通过 Vivado 软件对 Virtex -7 器件执行擦除、空白检查、编程和验证等配置操作。 本附录中的表格所列赛灵思系列非易失性存储器将不断保持更新 &#xff0c; 并支持通过 Vivado 软件对其中所列非易失性存储器 进行擦除、…

【Web后端】会话跟踪技术及过滤器

1.会话跟踪技术 1.1 会话的概念 在web应用中&#xff0c;浏览器和服务器在一段时间内发送请求和响应的连续交互的全过程 1.2 会话跟踪概念 对同一个用户跟服务器的连续请求和接收响应的监视过程 1.3 会话跟踪作用 浏览器和服务器是以http协议进行通信&#xff0c;http协议是…

day12-多线程

多线程 1.为什么要学习多线程 生活:流水线打工 public static void main(String[] args) { // 代码… for (int i 0; i < 10; i) { System.out.println(i); } // 代码... }多线程:多&#xff08;个&#xff09; 线程 1.1 进程和线程 线程&#xff1a;是进程中的…

Java日志总结

开发中&#xff0c;日志记录是不可或缺的一部分&#xff0c;应用日志的记录主要用于&#xff1a;记录操作轨迹数据、监控系统运行情况、系统故障定位问题&#xff0c;日志的重要性不言而喻&#xff0c;想要快速定位问题&#xff0c;日志分析是个重要的手段&#xff0c;Java也提…

企业信息系统的总体框架

1.信息系统体系结构的总体参考框架 信息系统的架构&#xff08;Information System Architecture&#xff0c;ISA&#xff09;中的Architecture含义具有丰富内涵和作用&#xff0c;相比计算机领域的Architecture来说它的单一性、片面性模型是难以描述ISA的全部的&#xff0c;IS…

docker八大架构之单机架构

单机架构 什么是单机架构&#xff1f; 单机架构指的是应用服务和数据库服务公用同一台服务器。如下边两个图所示&#xff0c;当我们进行购物时&#xff0c;所有的物品信息和用户信息都是在同一个服务器下进行运行的&#xff0c;之所以称为单机架构就是因为它所有的操作是在同…

文心一言 VS 讯飞星火 VS chatgpt (257)-- 算法导论19.2 1题

一、给出图19-4(m)中的斐波那契堆调用 FIB-HEAP-EXTRACT-MIN 后得到的斐波那契堆。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 由于我不能直接画出图19-4(m)中的斐波那契堆&#xff0c;我将基于斐波那契堆的基本结构和操作FIB-HEAP-EXTRACT-MIN的一般行为来…

HTTPS对于网站到底价值几何?

现在HTTPS基本上已经是网站的标配了&#xff0c;很少会遇到单纯使用HTTP的网站。但是十年前这还是另一番景象&#xff0c;当时只有几家大型互联网公司的网站会使用HTTPS&#xff0c;大部分使用的都还是简单的HTTP&#xff0c;这一切是怎么发生的呢&#xff1f; 为什么要把网站…

根据蛋白质序列,计算其分子量(molecular weight),在线工具,原理和python代码

蛋白质分子量 蛋白质是由许多氨基酸残基通过肽键&#xff08;一个氨基酸的 α-羧基与另一个氨基酸的 α-氨基脱水缩合形成的化学键&#xff09;连接而成。蛋白质的分子量&#xff08;molecular weight&#xff09;为各个氨基酸的分子量之和&#xff0c;是蛋白质的重要理化参数…

速戳!高考生做近视手术须知,避免错过心仪大学

距离高考还有不到一个月的时间&#xff0c;考生们在紧张复习的同时&#xff0c;不要忘了了解意向专业、院校的视力要求。一些专业和院校录取不仅靠实力,还需要“视力”,考了个好成绩却因视力不达标而被专业、院校退档,这样的结果是我们不想看到的。如果你想圆军旅梦、警校梦、航…

面向对象设计(下)《Ⅱ》

文章目录 抽象类抽象类的理解&#xff08;抽象类不能实例化&#xff09; 设计模式模板方法设计模式代理模式工厂方法设计模式 接口接口的定义&#xff08;接口仅可以用public修饰&#xff09;接口的实现jdk1.8中接口的默认方法和静态方法 内部类成员内部类静态成员内部类的创建…

timerfd加epoll封装定时器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1、用timerfd加epoll封装定时器的优点2、代码实现 1、用timerfd加epoll封装定时器的优点 定时器为什么需要timerfd 在设计定时器时&#xff0c;我们首先想到的就是…

HNU-操作系统OS-2024期中考试

前言 该卷为22计科/智能OS期中考卷。 感谢智能22毕宿同学记忆了考卷考题。 同学评价&#xff1a;总体简单&#xff1b;第1&#xff0c;7概念题较难需要看书&#xff1b;第4&#xff0c;5题原题。 欢迎同学分享答案。 【1】共10分 操作系统的设计目标有哪些&#xff1f; 【…

Attention-guided Feature Distillation for Semantic Segmentation

摘要 与现有的复杂方法相比&#xff0c;该方法通常用于从老师那里提取知识给学生&#xff0c;该方法展示了一种简单而强大的方法&#xff0c;可以利用精细的特征映射来转移注意力。事实证明&#xff0c;该方法在提取丰富信息方面是有效的&#xff0c;在作为密集预测任务的语义…

springfox.documentation.spi.DocumentationType没有OAS_30(从swagger2转到swagger3出现的问题)

直接开讲&#xff1a; 查看源码根本没有OAS_30的类型选择 右键package的springfox找到maven下载的包&#xff0c;打开到资源管理器 可以看到项目优先使用2版本的jar包&#xff0c;但是OAS_30只在3版本中才有&#xff0c;意思就是让项目优先使用以下图片中的3.0.0jar包 解决办法…

智能文件夹改名助手:一键秒级恢复原始名称,轻松告别繁琐操作,提升文件管理效率

文件夹管理成为了我们日常工作和生活中不可或缺的一部分。然而&#xff0c;随着文件数量的不断增加和文件夹命名的复杂性&#xff0c;我们经常面临着重命名文件夹的繁琐操作。你是否曾经因为误改文件夹名称而头疼不已&#xff1f;是否曾经为了找回原始名称而耗费大量时间&#…

docker容器实现https访问

前言&#xff1a; 【云原生】docker容器实现https访问_docker ssl访问-CSDN博客 一术语介绍 ①key 私钥 明文--自己生成&#xff08;genrsa &#xff09; ②csr 公钥 由私钥生成 ③crt 证书 公钥 签名&#xff08;自签名或者由CA签名&#xff09; ④证书&#xf…

【Java】:向上转型、向下转型和ClassCastException异常

目录 先用一个生动形象的例子来解释向上转型和向下转型 向上转型&#xff08;Upcasting&#xff09; 向下转型&#xff08;Downcasting&#xff09; 向上转型 概念 例子 发生向上转型的情况 1.子类对象赋值给父类引用 2.方法参数传递 3.返回值 向下转型 概念 注意…