JAVA性能优化思路探究( 三 )


? 合理设置堆的大小,合理设置分代空间的划分:设置太小,容易GC频繁,设置太大,GC暂停时间太长 。同时,为了避免可能使用虚拟内存,内存页面交换导致速度变慢,至少要预留1G的物理内存 。
? 如何选择每个分区的大小要根据应用中对象生命周期的分布情况:如果应用有大量的短期对象,应该选择更大的年轻代;如果持久化对象比较多,老年代应该适当增加 。
? 稳定振荡的堆大小:使-Xms和-Xmx的大小相同,有利于垃圾回收 。
4.1.3 大对象分配优化
? 大对象尽量分配在TLAB中 。如果大量对象出现在 TLAB 之外,则需要考虑调整 TLAB 参数,或者减小分配对象的大小 。可以使用 -XX: 标志查看结果 。
? 将大对象分配给老年代:将大对象直接分配给老年代,维护新生代对象的结构完整性提高GC效率,通过-XX:ld设置进入老年代的阈值 。
4.2 java编程优化
因为在实际编程中,性能优化涉及的点很多,以下只是一些常见的优化项,供参考 。
4.2.1 线程池优化
? 根据当前服务器CPU数,合理设置最大线程数、最小线程数、线程池任务队列大小 。对于 CPU 密集型任务,尽量少配置线程,比如配置一个 Ncpu+1 线程的线程池 。对于IO密集型任务,由于线程并不总是在执行任务,所以尽量配置多线程,比如2*Ncpu 。
? 推荐使用有界队列,可以增加系统的稳定性和预警能力 。
? 不同优先级的任务可以使用优先级队列进行处理 。
? 执行时间不同的任务可以交给不同大小的线程池处理,也可以使用优先队列让执行时间短的任务先执行 。设置线程的优先级 。
4.2.2 其他编程细节
? 最小化内存使用,减小对象大小,设置类型时考虑最小化原则,移除未使用的属性,以及未使用的实例变量 。
? 通过使用对象池和线程局部变量来增强对象复制 。对象复用和GC有点矛盾,所以主要考虑对象初始化的成本比较高(也就是初始化时间比较长) 。
? 对于保存同步对象的对象,实际上并不需要在多个线程之间共享,而且还要在不同的现实中传输对象,考虑使用线程局部变量来减少同步竞争 。
? 在某些场景下,优化使用java8并行流的方式
4.3 数据库优化
4.3.1 使用预编译
使用该方法,复用pool可以大大提升性能,同时避免大量大对象池化带来的GC问题 。
4.3.2 使用连接池
引入连接池并在启动时进行配置
? 创建连接的成本非常高 。通过JDBC连接池获取连接可以节省创建连接的时间 。同时,需要合理设置连接池的大小 。
? 合理设置:例如设置检索时的batch值,设置最优预取值,设置batch值可以提高检索的性能 。
? 事务优化:事务的提交以及与事务相关的锁机制会影响系统的性能 。需要考虑事务隔离级别的合理设置和批量提交的策略 。
5 性能实践经验总结
5.1 清除并发性能没有提升
5.1.1 问题症状
在使用java8的并行流计算时,发现并发性能上不去,随着时间的推移性能会不断下降 。
5.1.2个优化点
? 引入连接池,将单笔延迟降低到5ms
? 关闭日志
? 将sql改为预编译模式
? 提升服务器内存
5.2 夏尔和中泰之间有很多联系
5.3 可以随意配置吗?
6 总结
6.1 性能工具箱
6.1.1 压力测量工具
Jmter 是一个开源的压力测量工具,也很容易使用 。它的使用就不介绍了,但是这里有一些需要注意的地方:
? 它的实时绘制依赖于服务器的响应 。如果压测仪和服务器时间不同步,会出现显示图故障现象 。为了获得更准确的性能曲线,建议使用命令行方式 。