JVM高性能调优宝典【包含VisualVM工具下载安装教程】持续更新优化

🤡一、JVM&JRE&JDK的关系

🥇二、类加载机制

(一)类加载的过程

(1)装载

①获取类的全限定类名,把class文件转为二进制流
②把二进制中类的概述信息转入方法区中,如:创建时间、版本
③将java.lang.Class对象存入堆中

在这里插入图片描述

(2)链接

①验证:验证被加载类的正确性:如文件的格式,元数据等
②准备:在方法区中为静态变量分配空间,并设置初始值
③解析:把类的符号引用转为直接引用

(3)初始化

为类的静态变量设置默认值,执行静态代码块

(二)类加载器的分类

启动类加载器:主要负责加载JAVA的一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar中
拓展类加载器: 主要加载JAVA中的一些拓展类,位于<JAVA_HOME>/lib/ext中,是启动类加载器的子类
应用类加载器:主要用于加载CLASSPATH路径下我们自己写的类是拓展类加载器的子类

(三)双亲委派模型

如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给符类加载器去执行,如果父类加载器还存在父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回。若父类加载器不能完成加载任务,子加载器才会尝试自己去加载
在这里插入图片描述

如何打破双亲委派机制?

自定义类加载器类,继承ClassLoader类,重写loadClass方法

🥈三、JVM内存模型

在这里插入图片描述

(一)程序计数器

程序计数器会记录当前线程要执行指令的内存地址,只占用一小部分内存区域,只记录一个地址,所以我们认为程序计数器是不会出现内存溢出问题的分区。

(二)本地方法栈

Java中有些代码的实现是依赖于其他非Java语言的,本地方法栈存储的是维护非Java语句执行过程中产生的数据,一般我们认为本地方法栈不会出现内存问题

(三)虚拟机栈

主要是用来存储基本数据类型,同时也存储对象类型的引用,引用地址占4个字节
在这里插入图片描述

(1)栈帧的结构

在这里插入图片描述

为什么a=a+1的效率低于a++的效率呢?

a=a+1要在操作数栈中进行运算,而a++只需要在局部变量中运算即可

局部变量:
存放当前方法的局部变量,基本数据类型存值i,引用数据类型存堆内存地址
操作数栈:
对方法中的变量提供技术的区域
常量数据的引用:
常量数据会存放到方法区的常量池中,不管是基本数据类型还是引用数据类型都会存放常量池的地址
方法返回值的地址:
方法返回数据会存到计算机内存的寄存器中

(2)栈溢出及调优

在这里插入图片描述

设置栈的深度
在这里插入图片描述

(四)方法区

在java8之后,我们把方法区称为元空间,方法区在逻辑上属于堆的一部分,但在一些具体机制和堆有所区别,如:一些JVM的方法区是可以不进行垃圾回收的,关闭JVM时才会释放方法区内存,所以方法去还有一个别名为非堆
方法区会存储类信息、静态变量、常量(jdk8之后不存放字符串常量)
如果加载大量class文件,也会造成方法区内存溢出,如一个tomcat运行20~30个项目

(五)堆内存

(1)Java对象内存布局

在这里插入图片描述
对象头
MarkWord:一系列标记位(哈希码,分代年龄、锁状态标记),在64位系统中占8位
ClassPoint:对象对应的类信息的内存地址,在64位系统中占8个字节
Length:数组对象特有,表示数组长度,占4字节
实时数据
包含了对象的所有成员变量,大小有各个变量类型决定
封装填充
为了保证对象的大小为8字节的整数倍

(2)JVM内存溢出和垃圾回收机制

①为什么要进行垃圾回收:

如果对象只创建不回收,会造成堆内存溢出异常

②为什么要进行堆内存分区:
  1. 提高搜索效率
  2. 垃圾回收后可以更好的利用内存空间,存放大对象
  3. 尽可能减少GC次数

(3)JVM堆内存的划分

在这里插入图片描述
老年代:
对象会优先分配到新生代内存中,每次GC后没有回收的对象年龄+1,年龄到15还没有被后手,对象会存放到老年代内存中,如果对象较大,超过新生代内存的一半,对象也会存放到老年代区域
新生代:
为了减少young垃圾回收后的空间碎片,新生代又分为了Eden区和两个Survivor区,且始终有一个Suvivor区保持闲置,对象会先存放到Eden区中,Eden区空间满了之后会进行young区的垃圾回收,之后将young区所有存活的对象复制到闲置的Suvivor区中,并且清空Eden区和正在使用Suvivor区

(4)YoungGC和OldGC

YoungGC
新生代区域的垃圾回收称为YoungGC,也叫MinorGC,Eden区满后会触发YoungGC
OldGC
老年代区域的垃圾回收称之为OldGC,也叫MajorGC,OldGC非常浪费性能,所以我们的JVM调优要尽可能减少OldGC的次数,OldGC往往伴随着YoungGC

(5)面试题

1.Survivor区空间并不大,如果满了怎么办?
(1)一般情况下GC回收95%的对象,且超过15次GC的对象会放到Old区,所以Survivor区不容易满
(2)如果Suvivor区满了,会触发担保机制,提前将对象存入old区
2.为什么需要Suvivor区?
为了减少垃圾回收带来的空间碎片,空间碎片过多会频繁出发YoungGC
3.为什需要俩个Suvivor区?
为了减少Suvivor区的空间碎片,如果只存在一个Suvivor区,则对象向从Eden区进入到Suvivor区,区满进行GC后,可能会产生空间碎片,采用两个Suvivor区,两区可以交替回收整理,减少空间碎片

❤️四、使用VisualVM监听JAVA进程的内存模型

(一)下载VisualVM

VisualVM在Java8以及之前都是不用下载的,在下载的java路径下的bin中
在这里插入图片描述
版本在8之后的得自行安装
下载链接:https://visualvm.github.io/

(二)安装以及使用

安装一路无脑下一步
下面就是初始页面
在这里插入图片描述

(1)编写代码测试各个内存区域

【一个简单的循环创建对象的方法】
在这里插入图片描述

(2)设置堆栈的起始和最终大小

-Xms10M -Xmx10M

设置成这样子可以更加直观的看到,新生代和年老代的变化,
在这里插入图片描述

(3)最后运行页面

在这里插入图片描述
在这里插入图片描述

(五)垃圾回收机制

(一)如何判断一个对象是垃圾

(1)引用计数法

如果要操作对象,必须通过引用来进行,如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了,这种方法实现简单,效率较高,但是它无法解决循环引用问题,因此在java中并没有采用这种方式(pyhon使用的是引用计数法)

循环引用问题:是指创建了两个属于同一个类的对象,这两个对象之间相互引用,如下图object,当我的object1和object2 不在指向那两个对象时,正常情况下,我们应该要把其回收掉,但是它们两个还有引用,所以采用引用计数法无法将他们回收!

图1

(2)可达性分析

  以一个GC ROOT 对象作为起点进行搜索,如果在GC ROOT和对象之间没有可达路径,则称该对象是不可达的。
GC ROOT对象

  • 栈帧中的本地变量表中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中引用的对象

(二)垃圾回收算法

(1)标记-清除算法

(2)复制算法

在这里插入图片描述

(3)标记-整理算法

在这里插入图片描述
在这里插入图片描述

(三)垃圾收集器

(1)垃圾收集器的评判标准

垃圾回收器是对垃圾回收算法的实现,JVM中提供了很多垃圾回收器,我们通过以下式子来评判垃圾回收器的好坏
垃圾回收器的执行效率= 吞吐量/停顿时间
吞吐量 = 用户代码执行时间/(用户代码执行时间+停顿时间)

(2)垃圾收集器分类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(3)详解并发垃圾回收器

①CMS收集器

  CMS(并发标记扫描)收集器是并发收集器,是基于标记-清理算法进行垃圾后手,用于OldGC
优点: 并发收集,低停顿
缺点: 会产生大量空间碎片,停顿时间虽然短但是不可控

为什么CMS收集器不进行并发的初始标记?
  因为标记垃圾所需要耗费的时间较少,没有必要再并发开启多线程,这样子会使程序更加耗费资源

②G1收集器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

③ZGC收集器

  ZGC从JDK11开始支持,目前还是实验性版本,原理类似G1,是目前效率最高的垃圾收集器,平均暂停时间为0.05毫秒

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

取酒鱼食--【余九】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值