Java 在 Linux 中性能调优最佳实践
Posted ImportNew
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 在 Linux 中性能调优最佳实践相关的知识,希望对你有一定的参考价值。
(给ImportNew加星标,提高Java技能)
编译:ImportNew/覃佑桦
www.coderbuzz.com/2019/12/04/performance-tuning-java-applications-in-linux
本文能帮助你把Java应用程序性能发挥到极值。
在应用程序进行性能调优时,应当在优化代码的同时考虑代码运行的硬件。本文将介绍在Linux上把Java性能推到极致需要注意的方方面面。
线程争用
减少关键部分的代码量。
优先考虑使用同步代码块,其次才是同步方法。
优先考虑在同步代码块上加锁。
密切注意锁定资源的顺序,你可能会遇到死锁。
隔离低并发、中等并发和高并发用例,区别对待。
对低并发和中等并发尽可能使用CAS(Compare-And-Swap)操作。
请勿在同步代码块或已加锁情况下调用第三方Web服务或执行其他需要长时间运行的方法。
对比wait、notify和notifyAll机制,更推荐lock、CountDownLatch、CyclicBarrier这样的高级线程结构。
长时间运行的线程应允许中断。线程内部定期检查“interrupted”状态。
当读操作数量远大于写操作时,建议使用ReadWriteLock。它提高了读操作并发性。
仅在有多个线程访问数据结构的情况下才考虑使用并发数据结构。
不要在应用程序中到处修改状态。对可变状态加以限制并有意识地进行处理。这样可以减少锁的数量以及各种线程争用问题。
注意下面的自旋锁。它们会占用CPU资源。while(true) {//执行操作不休眠}
在这种无限while循环中,一定要合理地休眠。轮询线程就是一个这样的示例。
堆配置与垃圾回收
遵守用StringBuilder处理日志消息的标准实践。
分析应用程序,设置合理的堆与和垃圾收集参数。
不合理的GC设置可能会占用CPU资源,造成应用程序长时间暂停,由于内存不足导致应用程序崩溃,以及因并发模式故障带来的内存溢出或应用假死。
为了保证低延迟,应用程序需使用并发标记(Concurrent Mark)以及 CMS 或 G1 GC扫描算法。
避免磁盘交换
务必保证有足够的RAM提供给Java进程,Java进程发生磁盘交换是性能杀手。如果应用程序交换到磁盘,由于在GC期间必须从磁盘读取对象,垃圾回收周期会更长。
磁盘
使用异步logger记录日志。
在允许的情况下采用上下文日志。上下文日志是指将API调用的日志或事件存储到上下文对象中,并通过异步logger记录上下文数据。这将大大提高Java应用程序的性能,并且更易于排除故障。
无论进行何种持久性,优先考虑数据库而非本地磁盘。数据库针对磁盘读写进行了优化。
CPU
使用线程池。尽管线程本身是轻量级,但是创建线程仍然会带来很大的开销。
盲目地创建线程会导致上下文切换与平均负载激增,超过指定的阈值后会造成应用程序和计算机无响应。
除了CPU利用率,还要注意平均负载和上下文切换。它们在一起组成了性能相关的完整信息。
密切注意网络
查找网络上的丢包情况。
数据包丢失可能意味着应用程序太忙无法接收数据包,或者所处的网络发生拥塞。
如果有必要,请调整网络缓冲区大小。
使用缓存
缓存常用数据减少数据库访问。
针对每个用例分别进行缓存配置,包括eviction、expiry、size、consistency和concurrency。
将读密集型缓存与写密集型缓存分开,这样获得更好的锁定效果。
谨慎地使用分布式缓存。不恰当地使用分布式缓存会引入新问题,而不是解决现有问题。
通讯
对于近距离实时通信优先考虑异步通信。
设置发送API或RMI调用超时,这样某个长时间运行的操作不会破坏整个生态系统。
分析并记录更改
持续进行性能分析并记录你的更改。清晰地记录做出决定的原因。今天的重大决策可能到了明天就失去意义。这种情况发生时,工程师应该有足够的信息来还原或扩展应用程序。这就是应用程序的生存之道。没有人愿意坐在一颗定时炸弹上,并且不知道它什么时候会爆炸。
性能分析工具
Jstack用来收集线程dump。
Jmap用来收集堆dump和活动对象计数。
Jvisualvm或Jconsole:用来分析堆、线程、收集线程dump,JDK默认提供。
Eclipse内存分析器(MAT):用来分析堆dump。
线程Dump分析器(TDA):用来分析线程dump,检测长时间运行的线程与死锁。
性能调优建议
在项目早期就进行性能调整计划和预算,但不要过早开始执行。这样可能会让核心业务逻辑变得混乱。我知道有一个应用程序过早进行优化,限制从数据库中获取的记录数,但是这一切并没有记录。
结果出现了各种各样的问题。由于这段代码位于底层,导致花了很多时间才得以解决。当然,如果在这方面你已经身经百战,可以忽略这条建议。
推荐阅读
(点击标题可跳转阅读)
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能
好文章,我在看❤️
以上是关于Java 在 Linux 中性能调优最佳实践的主要内容,如果未能解决你的问题,请参考以下文章