(JVM调优)GC调优
GC调优GC调优指的是对JVM的垃圾回收部分进行调优,其目标是避免由垃圾回收引起的程序性能下降;
其调优的核心分为三部分
通用JVM参数的设置
特定垃圾回收期的JVM参数设置
解决频繁的Full GC造成的性能问题
GC调优的核心指标
业务吞吐量:一段时间内程序需要完成的业务数量
垃圾回收吞吐量:CPU用于执行用户代码的时间与CPU总执行时间的比值
延迟:用户发起一个请求到收到相应之间经历的时间
内存使用量:Java程序占系统内存的最大值,在满足上面的指标的前提下,内存用量越少越好
GC调优的方法GC调优与内存调优一样,也是分为 发现->诊断->修复->验证 四个阶段
发现阶段我们可以通过使用jstat工具,visualvm插件,Prometheus + Grafana,观察GC日志,GC Viewer工具,GCeasy工具来帮助我们发现问题
诊断阶段CG的正常情况呈现锯齿状,对象创建后内存使用增加,在经过垃圾清理后大幅回落,且每次回收之后的使用内存大小接近,留存对象较少
缓存对象过多的情况与正常情况类似,但是在清理后的内存占用仍然较高
原因:程序中保存了大量 ...
(JVM调优)内存调优
内存调优什么是内存泄露Java中如果一个对象不再被使用,但他仍在GC ROOT的引用链上,根据之前提到的回收办法,他就不会被垃圾回收器回收,这就造成了内存泄露。内存泄漏往往发生在堆区。
下面列举几个内存泄露的常见场景
在Java后端程序中处理完用户请求后未及时将用户数据删除,随着用户数据不断累积,造成堆内存溢出
进行分布式调度时被调度的应用在调度结束时出现了内存泄漏,多次调度后内存溢出
内存泄露的解决方案对于内存泄露,常常按照四步来解决
发现问题阶段常使用阿里开发的Arthas工具来对业务状态进行监看
而Prometheus+Grafana是企业中运维常用的监控方案
在使用上面的工具对堆内存状况进行监看,我们可以发现出现内存泄漏时,堆内存会出现明显异常
诊断阶段原因1: 内存中的代码泄露
equals()和hashCode()的不正确使用,导致同一数据被保存多次
ThreadLocal的使用过程中未回收线程池中的线程;
线程方法执行完毕后,一定要调用ThreadLocal中的remove方法来清理对象
通过静态字段来保存对象,造成大量数据在静态变量中被引用,但又不被使用
...
(JVM)JVM笔记汇总
JVM笔记JVM启动流程1. 配置JVM装载环境JVM的环境创建包括两部分: JVM.dll文件的查找和装载
JVM.dll文件的查找:首先查找系统环境变量中的PATH路径中有没有JVM的相关配置,如果没有,则继续查找环境变量中的JAVA_HOME路径中的JVM.dll。若在JAVA_HOME中也找不到,就会在注册表中查找,如果连注册表里都找不到,JVM就无法启动了。
JVM.dll文件的装载:LoadLibrary方法装载JVM.dll动态连接库。然后把JVM.dll文件中定义的函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs绑定到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上;
2. 解析虚拟机参数将JVM环境装入内存后,接下来要做的就是解析JVM的参数
JVM在启动时,会将传递给它的命令行参数存储到一个字符串数组,之后JVM会遍历该数组,解析每个参数
JVMM会根据参数的格式和语义进行解析和处理,常见的虚拟机参数包括
标准虚拟机参数: -Xm ...
(JVM)JVM的垃圾回收机制
垃圾回收机制Java程序不要求我们手动操作内存,而是由JVM为我们提供了一套全自动的内存管理机制,JVM会自动判断对象的回收时机
对象存活判定算法既然要回收内存空间,就需要判断对象在什么时候需要被JVM回收,下面介绍一些常用的垃圾回收算法
引用计数法通常在操作对象时,我们操作的是对象的引用,这样就会创建一个引用变量
12String str = "This is a String."; //这里的str就是一个引用对象,我们通过引用对象来操作对象str = null; //此时str不再指向上面的对象
我们Java程序员通常是通过引用变量来操作对象的,这样如果一个对象还有操作价值,我们就会用它的引用变量来操作它;因此,我们可以通过引用变量的计数来判断一个对象是否还在被使用
JVM会为每个对象都创建一个引用计数器,存放该对象被引用的次数
每当有新的引用变量指向该对象时,就会让 该对象的引用对象 + 1
当引用对象指向其他地方或设为null时,会让 该对象的引用对象 - 1
当该对象的引用计数为0时,就可以看做本对象已经不再被使用了
这样会存在两个对象相互引用的问题 ...
(JVM)JVM的内存管理
内存管理在Java中,不允许使用指针等工具来直接操作物理内存,对于内存的操作时由JVM来代我们进行处理的,虽然这样让Java的内存管理变得简单,但是这样降低了Java操作内存的效率,同时如果JVM在内存操作时出现了问题,难以找到出问题的点。
内存区域划分JVM将内存划分为如下的区域
内存一共分为:方法区、堆区、虚拟机栈、本地方法栈和程序计数器五个区域。
其中方法区和堆区是由所有线程共享的区域,其随着虚拟机的创建而创建,随着虚拟机的销毁而销毁。
对于虚拟机栈、本地方法栈和程序计数器是线程之间相互隔离的,每个线程都有自己的这三块区域,其生命周期与线程的生命周期保持一致。
程序计数器JVM中的程序计数器PC和我们学计组的PC差不多是一个概念,其目的就是让Java虚拟机像物理机那样执行程序。
不同于8086CPU中PC记录下一条指令的地址,JVM中的PC可以看做是当前线程所执行的字节码的行号的指示器,每当一条指令执行完毕,就会读取下一条应该执行的指令的行号并存入PC中
Java的多线程是依靠时间片轮转算法来进行的,每个线程在其所占有的时间片终结时,会保存当前执行位置到PC中,当该线程再次抢占 ...
(JVM)JVM的启动流程
JVM启动流程1. 配置JVM装载环境JVM的环境创建包括两部分: JVM.dll文件的查找和装载
JVM.dll文件的查找:首先查找系统环境变量中的PATH路径中有没有JVM的相关配置,如果没有,则继续查找环境变量中的JAVA_HOME路径中的JVM.dll。若在JAVA_HOME中也找不到,就会在注册表中查找,如果连注册表里都找不到,JVM就无法启动了。
JVM.dll文件的装载:LoadLibrary方法装载JVM.dll动态连接库。然后把JVM.dll文件中定义的函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs绑定到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上;
2. 解析虚拟机参数将JVM环境装入内存后,接下来要做的就是解析JVM的参数
JVM在启动时,会将传递给它的命令行参数存储到一个字符串数组,之后JVM会遍历该数组,解析每个参数
JVMM会根据参数的格式和语义进行解析和处理,常见的虚拟机参数包括
标准虚拟机参数: -Xms: 堆的 ...