JVM调优(三)程序代码调优

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bbbbln/article/details/82805725

根据第一节所讲的基础知识,我们根据线上不同的异常情况做程序的优化。

CPU占用高

us高

根据之前的分析,CPU us高的原因主要是执行线程无任何挂起动作,且一直执行,导致CPU没有机会去调度执行其他的线程,造成线程饿死的现象。对于这种情况,常见的一种优化方法是对这种线程的动作增加Thread.sleep,以释放CPU的执行权,降低CPU的消耗。对于线程要不断扫描某种状态,达到自己的可继续运行下去的条件时再运行(像代码while(xxx==yyy)),使用wait/notifyAll会比较好。

sy高

CPU sy高的原因主要是线程的运行状态要经常切换,

另处一个原因是锁竞争激烈,造成线程状态切换。

方案:最简单的优化方法是减少线程数。若系统要支持大量并发的话,最好建立线程队列来缓解压力。

注意:降低线程数后,可能造成sy降低,us升高。

若无法降低线程数,可采用协程,以支持更高并发量。粒度上协程比线程小,线程不用频繁切换。(协程在java里还不太成熟,但是可以大胆往这方面尝试。)

文件IO消耗严重

从程序角度而言,造成文件IO消耗严重的原因主要是多个线程将大量的数据写到同一文件,导致文件很快变得很大,从而写入速度越来越慢,并造成各线程激烈争抢文件锁。

方案:

异步写文件,避免写入慢导致应用性能下降太多。(如日志采用log4j的AsyncAppender)

批量读写

限流,将读写IO降低到一个能接受的范围。(时间窗,停牌桶等)。

限制文件大小,大文件读或者追加写动作会增加耗时,限制文件大小后,超过一定值新生成文件。

网络IO消耗

方案:限流,控制发送频次。

内存消耗

释放不必要的引用。典型如ThreadLocal,在线程结束时,这里面的内容不会主动释放,会造成内存增大。查看!ThreadLocal使用不当后果

使用对象缓存池创建对象的实例要耗费一定的CPU以及内存,使用对象缓存池一定程度上可降低JVM Heap内存的使用。(慎用,使用不当会造成内存增大)。但是引入合理的缓存失效机制,会改善内存占用。如FIFO,LRU,LFU。

LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面。LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页。

合理使用SoftReference和WeakReference对于占据内存但又不是必须存在的对象,例如缓存对象,也可以基于SoftReference或WeakReference的方式来进行缓存。

猜你喜欢

转载自blog.csdn.net/bbbbln/article/details/82805725