写点什么

阿里巴巴 Java 性能调优实战

作者:Joseph295
  • 2022 年 5 月 02 日
  • 本文字数:1761 字

    阅读完需:约 6 分钟

阿里巴巴Java性能调优实战

概述

哪些参考因素可以体现系统的性能?

CPU:有的应用需要大量计算,他们会长时间、不间断占用 CPU 资源,导致其他资源无法争夺到 CPU 而响应变慢。例如,代码递归导致无限循环,正则表达式引起的回溯,JVM 频繁的 Full GC,以及多线程造成的大量上下文切换等。

内存:Java 程序一般通过 JVM 对内存进行分配管理,但当内存空间被占满,对象无法回收时,就会导致内存溢出、内存泄漏等问题

磁盘 I/O:磁盘相比内存来说,存储空间大很多,但读写速度也慢很多。

网络:这个不展开

异常:Java 应用中,抛出异常需要构建异常栈,对异常进行捕获和处理,这个过程非常消耗系统性能。如果在高并发的情况下引发异常,持续进行异常处理,那么系统的性能就会明显受到影响。

数据库:大部分系统会用到数据库,数据库的操作往往涉及到磁盘 IO 读写,大量的数据库读写操作,会导致磁盘 IO 性能瓶颈,进而导致数据库操作的延迟性。对于有大量数据库读写操作的系统来说,数据库的性能优化是整个系统的核心。

锁竞争:为了保证操作的原子性,我们会用到锁。锁的使用会带来上下文切换。Java 1.6 之后,Java 为了降低锁竞争带来的上下文切换,对 JVM 内部锁做了多次优化,如增加了偏向锁、自旋锁、轻量级锁、锁粗化、锁消除等。

响应时间


数据库响应时间:往往是整个请求链中最耗时的

服务端响应时间:包括 Nginx 分发请求所消耗的时间以及服务端程序执行所消耗的时间

网络响应时间:网络传输时,网络硬件对请求解析等操作的耗时

客户端响应时间

吞吐量

我们可以把吞吐量自上而下地分为两种:磁盘吞吐量和网络吞吐量。

一种是 IOPS,指单位时间内系统能处理的 IO 请求数量,IO 请求通常为读写数据操作请求,关注的是随机读写性能。适用于随机读写频繁的应用,如小文件存储(图片)、OLTP 数据库、邮件服务器等。

另一种是数据吞吐量,指单位时间内可以成功传输的数据量。对于大量顺序读写频繁的应用,传输大量连续数据,数据吞吐量是关键衡量指标。

网络吞吐量:在没有丢帧的情况下,网络设备能接受的最大数据速率。

如何制定性能调优策略?

测试-分析-调优

性能测试攻略

  1. 微基准性能测试

  2. 宏基准性能测试


字符串性能优化

String str1 = "abc";String str2 = new String("abc");String str3 = str2.intern();assertSame(str1 == str2); // falseassertSame(str2 == str3); // falseassertSame(str1 == str3); // true
复制代码

Java 语言的工程师们对 String 对象做了大量优化,来节约内存空间,提升 String 对象在系统中的性能。

  1. 在 Java 6 以及之前的版本中,String 对象是对 char 数组进行封装实现的对象,主要由四个成员变量:char 数组、偏移量 offset、字符数量 count、哈希值 hash。String 对象通过 offset 和 count 两个属性来定位 char[] 数组,获取字符串。这么做可以高效、快速地共享数组对象,同时节约内存空间,但这种方式可能会导致内存泄漏(即只使用了 char 数组的一小部分,但整个数组无法释放)

  2. 从 Java 7 版本开始到 Java 8 版本,Java 对 String 类做了一些改变。String 类中不再有 offset 和 count 两个变量,好处是 String 对象占用内存稍微少了些,同时 String.substring 也不再共享 char[] ,从而解决了使用该方法可能导致内存泄漏问题。

  3. 从 Java 9 版本开始,将 char[] 字段改为 byte[] 字段,又维护了一个新的属性 coder。因为 char 占两个字节,JDK 1.9 的 String 类为节约内存空间,使用 byte 数组来存放字符串。coder 属性有两个值,0 代表 Latin-1(单字节编码),1 代表 UTF-16

String 对象不可变行的好处:

  1. 保证 String 对象的安全性。

  2. 保证 hash 属性不会频繁更改,确保唯一性,使得类似 HashMap 容器能实现相应的 key-value 缓存功能。

  3. 实现字符串常量池。

在 Java 中通常有两种创建字符串对象的方式,一种是 String str = "abc"; 另一种是 String str = new String("abc"); 第一种方式创建字符串时,JVM 首先检查该对象是否在字符串常量池中,如果在,就返回该对象的引用,否则新的字符串将在常量池中被创建。这种方式可以减少同一个值的字符串对象的重复创建,节约内存。第二种方式,首先在编译类文件时,"abc" 常量字符串将会放入到常量结构中,在类加载时,"abc" 将会在常量池中创建;其次,在调用 new 时,JVM 命令将会调用 String 的构造函数,同时引用常量池中的 "abc" 字符串,在堆内存中创建一个 String 对象,最后 str 将引用 String 对象。


String 对象的优化


用户头像

Joseph295

关注

三脚猫的技术 2018.03.14 加入

coder

评论

发布
暂无评论
阿里巴巴Java性能调优实战_Joseph295_InfoQ写作社区