首先的问题是性能调优包含哪些步骤,会有什么样的性能问题,性能调优调哪方面,怎么调。
基本的步骤就是先寻找性能瓶颈的位置,进而分析是什么样的条件导致了性能瓶颈。
对于Java程序来说,主要出现性能瓶颈的地方是cpu、IO(文件和网络两部分)、内存(jvm堆内存和堆外内存)。下面根据不同部分的问题分点总结。
CPU:更多的是线程问题
对于Java应用而言,CPU消耗严重主要体现在us、sy两个值上边。
us:Java应用造成us值高的原因主要是线程一直处于可运行状态(Runnable),通常是这些线程在执行无阻塞、循环、正则或纯粹计算导致的,另一个可能的情况就是频繁的GC。
要找出有问题的线程就要利用命令行工具和一些分析软件,获得线程ID等详细信息,再进行下一步处理。
Sy:当sy值高时,表示系统花费了大量时间在进行线程切换,Java应用中造成这些的主要原因是启动的线程比较多,且一直不断处于阻塞状态(锁等待、IO阻塞)和可运行状态间的不断切换,这就导致了大量的线程状态切换,产生大量的上下文切换。
这个部分的问题重要的是要找出导致线程不断进行切换的原因,需要dump出锁竞争激烈的线程进行分析。
文件IO分析:
Linux在操作文件时,会将文件放入文件缓存区,直到内存不够或者系统要释放内存给用户进程使用,再查看Linux内存状况时经常会发现可用的物理内存不多,但cached用了很多,这是Linux提升文件IO速度的一种方式。
在Linux中,主要通过pidstat、iostat来查看IO情况
网络IO分析:
对于Java应用而言,网络IO的消耗也很值得关注,尤其要注意网卡中断是不是均匀的分配到各CPU上。
Linux中用sar分析网络IO情况
内存消耗分析:
根据前面知识的学习,我们知道,内存消耗主要是在jvm堆上的(Java应用只会在线程创建和使用Direct ByteBuffer时才会操作堆以外的内存)。Jvm内存消耗过多会导致频繁的GC,CPU消耗增加,应用的线程的执行速度下降,甚至会造成OOM,最终导致进程退出。
分析jvm内存消耗的工具和方法前面已经提到。
对于内存方面的消耗,最值得关注的是swap和物理内存的消耗,在Linux中可以使用vmstat、sar、top、pidstat等查看swap和物理内存的情况。
对物理内存分析:
物理内存同样基于GC清理。
内存分析的基本步骤:
资源消耗不多但程序执行慢分析:
主要有锁竞争激烈、未充分使用硬件资源、数据量增长三种情况
调优
找到了性能瓶颈,分析了原因,接下来就该调优了。
代大小调优:
- 避免新生代大小过小:Minor GC频繁
- 避免新生代设置过大:老年代变小,Full GC频繁、MinorGC时间大幅增加
- 避免Survivor区过大或过小
- 合理设置新生代存活周期
GC调优策略:
这部分举个web应用的例子
GC的选择和调优要结合实际的应用情况来进行,不同的应用对垃圾收集的需求是不一样的。
程序调优
Cpu消耗严重的解决方法:
- us高的解决方法:
- sy值高的解决方法:
文件IO消耗严重的做法:
网络IO消耗严重的方法:
对于内存消耗严重的情况:
1.释放不必要的引用
2.使用对象缓存池:这种方式可以避免创建对象所消耗的时间和频繁GC造成的损耗。
3.采用合理的缓存失效算法:
4.合理使用软引用和虚引用
资源消耗不多但程序执行慢的原因:
锁竞争激烈:使用并发包、使用Teriber算法、使用非阻塞队列算法、少用锁、拆分锁、去除读写互斥锁。
未充分使用硬件资源
未充分使用CPU:主要是由于在能并行处理的时候没有用到足够多的线程
未充分使用内存:
最后,可以初步了解到,Java应用的问题主要就是出现在三个方面:CPU、IO、内存,另外还有一些不在此问题里的资源够用但还是慢,这时需要重点关注锁的问题。
调优是需要实战积累的,在实际情况中会使用到工具等帮助进行分析和调优,对内容进行综合。