京东架构师呕心整理:jvm与性能调优有哪些核心技术知识点

简介: 相信很多人对于性能调优都不陌生,为了获得更好的系统性能,或者是为了满足不断增加的业务需求。都需要用到我们的性能调优。所以性能优化在面试中出现的频率特别高,这篇文章我主要给大家整理了大厂里面关于jvm和性能调优用到的一些核心技术知识点。

相信很多人对于性能调优都不陌生,为了获得更好的系统性能,或者是为了满足不断增加的业务需求。都需要用到我们的性能调优。所以性能优化在面试中出现的频率特别高,这篇文章我主要给大家整理了大厂里面关于jvm和性能调优用到的一些核心技术知识点。


注意,注意,整个对于jvm和性能调优的知识点整理会很详细,文中所有的细节并不会全展示给大家,大家觉得对自己有帮助的朋友可以点击此处获取

目录:

  • JVM 内存区域划分
  • JVM 执行子系统
  • 垃圾回收器和内存分配策略
  • 编写高效优雅 Java 程序
  • 性能优化

JVM 内存区域划分


1.程序计数器(线程私有)

程序计数器(Program Counter Register),也有称作为 PC 寄存器。保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当 CPU 需要执行指令时,需要从程序计数器中得到当前需要执行的指令所在存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加 1 或者根据转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令。也就是说是用来指示执行哪条指令的

由于在 JVM 中,多线程是通过线程轮流切换来获得 CPU 执行时间的,因此,在任一具体时刻,一个 CPU 的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。

在 JVM 规范中规定,如果线程执行的是非 native 方法,则程序计数器中保存的是当前需要执行的指令的地址;如果线程执行的是 native 方法,则程序计数器中的值是 undefined。

由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。

异常情况:不存在

2.Java 栈(线程私有)

Java 栈也称作虚拟机栈(Java Vitual Machine Stack)

Java 栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表、操作数栈指向当前方法所属的类的运行时常量池的引用方法返回地址额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于 Java 栈的顶部


局部变量表,用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象引用。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。


3.本地方法栈(线程私有)


2.可扩展深度大于能够申请的内存:OutOfMemoryError

4.堆(线程共享)


5.方法区(线程共享)


6.直接内存(线程共享)


JVM 执行子系统


1.Class 类文件结构


2.字节码指令


3.类加载机制


4.类加载器


5.Tomcat 类加载机制


6.方法调用详解


三.垃圾回收器和内存分配策略


1.Java 中是值传递还是引用传递?

但是传引用的错觉是如何造成的呢?在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。所以这个修改是可以保持的了。

对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

2.引用类型

对象引用类型分为强引用、软引用、弱引用和虚引用

强引用:就是我们一般声明对象是时虚拟机生成的引用,强引用环境下,垃圾回收时需要严

格判断当前对象是否被强引用,如果被强引用,则不会被垃圾回收

软引用:软引用一般被做为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机

会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟

机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟

机在发生 OutOfMemory 时,肯定是没有软引用存在的。

弱引用:弱引用与软引用类似,都是作为缓存来使用。但与软引用不同,弱引用在进行垃圾

回收时,是一定会被回收掉的,因此其生命周期只存在于一个垃圾回收周期内。

强引用不用说,我们系统一般在使用时都是用的强引用。而“软引用”和“弱引用”比较少见。

他们一般被作为缓存使用,而且一般是在内存大小比较受限的情况下做为缓存。因为如果内

存足够大的话,可以直接使用强引用作为缓存即可,同时可控性更高。因而,他们常见的是

被使用在桌面应用系统的缓存。

3.基本垃圾回收算法


4.分代处理垃圾


5.JAVA 中垃圾回收 GC 的类型

由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC 有两种类型:ScavengeGC Full GC。

Scavenge GC: 一般情况下,当新对象生成,并且在 Eden 申请空间失败时,就会触发Scavenge GC,对 Eden 区域进行 GC,清除非存活对象,并且把尚且存活的对象移动到Survivor 区。然后整理 Survivor 的两个区。这种方式的 GC 是对年轻代的 Eden 区进行,不会影响到年老代。因为大部分对象都是从 Eden 区开始的,同时 Eden 区不会分配的很大,所以 Eden 区的 GC 会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden 去能尽快空闲出来。

Full GC: 对整个堆进行整理,包括 Young、Tenured 和 Perm。Full GC 因为需要对整个对进行回收,所以比 Scavenge GC 要慢,因此应该尽可能减少 Full GC 的次数。在对 JVM调优的过程中,很大一部分工作就是对于 FullGC 的调节。有如下原因可能导致 Full GC:· 年老代(Tenured)被写满、持久代(Perm)被写满、System.gc()被显示调用 、上一次 GC之后 Heap 的各域分配策略动态变化。

四、编写高效优雅 Java 程序


1.面向对象


2.方法


3.通用程序设计

3.1 用枚举代替 int 常量

声明的一个枚举本质就是一个类,每个具体的枚举值就是这个枚举类的实例。枚举更多作用,看代码。

3.2 将局部变量的作用域最小化

1. 在第一次使用的地方进行声明

2. 局部变量都是要自行初始化,初始化条件不满足,就不要声明

最小化的好处,减小局部变量表的大小,提示性能;同时避免局部变量过早声明导致不正确的使用。

3.3 精确计算,避免使用 float 和 double

可以使用 int 或者 long 以及 BigDecimal

3.4 当心字符串连接的性能

参考代码
com.xiangxue.ch04.StringUnion15.Test。

在存在大量字符串拼接或者大型字符串拼接的时候,尽量使用 StringBuilder 和 StringBuffer

五、性能优化


1.常用的性能评价/测试指标


2.常用的性能优化手段


3 应用服务性能优化


总结:

jvm性能调优一直是大厂面试的一个重点:上面的jvm性能调优的话没有将所有的知识点细节整理出来给大家,所有的核心技术知识点都整理到了PDF文档上面,出去jvm性能调优的核心知识点整理外,小编还整理了关于有java集合,微服务,kafka,设计模式,等核心知识点的整理。

资料获取方式:点击此处获取

更多核心知识点截图:



相关文章
|
11月前
|
存储 调度 C++
16 倍性能提升,成本降低 98%! 解读 SLS 向量索引架构升级改造
大规模数据如何进行语义检索? 当前 SLS 已经支持一站式的语义检索功能,能够用于 RAG、Memory、语义聚类、多模态数据等各种场景的应用。本文分享了 SLS 在语义检索功能上,对模型推理和部署、构建流水线等流程的优化,最终带给用户更高性能和更低成本的针对大规模数据的语义索引功能。
740 75
|
存储 数据挖掘 BI
2-5 倍性能提升,30% 成本降低,阿里云 SelectDB 存算分离架构助力波司登集团实现降本增效
波司登集团升级大数据架构,采用阿里云数据库 SelectDB 版,实现资源隔离与弹性扩缩容,查询性能提升 2-5 倍,总体成本降低 30% 以上,效率提升 30%,助力销售旺季高效运营。
727 9
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
人工智能 API 数据安全/隐私保护
Apifox 与 Apipost 的 API 文档引擎对比:底层架构、性能与可扩展性分析
深入探索市场上两大主流API工具——Apifox和Apipost的文档能力时,发现了令人惊讶的差距。这不仅仅是功能多寡的问题,更关乎开发效率与团队协作的质变。
|
SQL 缓存 分布式计算
vivo 湖仓架构的性能提升之旅
聚焦 vivo 大数据多维分析面临的挑战、StarRocks 落地方案及应用收益。 在 **即席分析** 场景,StarRocks 使用占比达 70%,查询速度提升 3 倍,P50 耗时从 63.77 秒缩短至 22.30 秒,查询成功率接近 98%。 在 **敏捷 BI** 领域,StarRocks 已完成 25% 切换,月均查询成功数超 25 万,P90 查询时长缩短至 5 秒,相比 Presto 提升 75%。 在 **研发工具平台** 方面,StarRocks 支持准实时数据查询,数据可见性缩短至 3 分钟,查询加速使 P95 延迟降至 400 毫秒,开发效率提升 30%。
vivo 湖仓架构的性能提升之旅
|
12月前
|
存储 JSON 数据处理
ClkLog埋点与用户行为分析系统:架构升级与性能全面提升
随着越来越多企业在实际业务中使用 ClkLog,数据规模和分析需求也不断提升,部分用户日活已经超过10万,为了顺应这一趋势,ClkLog 秉持 “开放透明、持续演进”的理念,推出了迄今为止最重要的一次性能优化升级。新版本在大规模数据处理与复杂查询场景中,性能表现实现了跨越式提升。经过多轮研发与严格测试,新版本现已正式上线:在原有付费版 1.0 的基础上架构全面升级,并同步发布全新的 2.0 版本。为用户带来更强的性能与更广的适用场景。
|
关系型数据库 MySQL 分布式数据库
Super MySQL|揭秘PolarDB全异步执行架构,高并发场景性能利器
阿里云瑶池旗下的云原生数据库PolarDB MySQL版设计了基于协程的全异步执行架构,实现鉴权、事务提交、锁等待等核心逻辑的异步化执行,这是业界首个真正意义上实现全异步执行架构的MySQL数据库产品,显著提升了PolarDB MySQL的高并发处理能力,其中通用写入性能提升超过70%,长尾延迟降低60%以上。
|
存储 缓存 分布式计算
高内存场景必读!阿里云r7/r9i/r8y/r8i实例架构、性能、价格多维度对比
阿里云针对高性能需求场景,一般会在活动中推出内存型r7、内存型r9i、内存型r8y和内存型r8i这几款内存型实例规格的云服务器。相比于活动内的经济型e和通用算力型u1等实例规格,这些内存型实例在性能上更为强劲,尤其适合对内存和计算能力有较高要求的应用场景。这些实例规格的云服务器在处理器与内存的配比上大多为1:8,但它们在处理器架构、存储性能、网络能力以及安全特性等方面各有千秋,因此适用场景也各不相同。本文将为大家详细介绍内存型r7、r9i、r8y、r8i实例的性能、适用场景的区别以及选择参考。