性能调优的层次
- 设计调优
- 代码调优
- JVM调优
- 数据库调优
- 操作系统调优
设计调优
善用设计模式
单例模式
单例模式是一种对象的创建模式,用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。好处;
1> 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销
2> 确保一个类只有一个对象,每次调用都是同一个对象,减少new的操作次数,降低对系统的内存的使用频率,减轻GC压力,缩短GC停顿时间
代理模式
将消耗资源最多的方法都使用代理模式分离,就可以加快系统的启动速度,减少用户的等待时间。
核心其实就是使用延迟加载,只有当用到了当前的组件时,才会去初始化他。这样如果有些组件没有被用到,就不用加载,避免资源的浪费
享元模式
如果一个系统中存在多个相同的对象,那么只需共享一份对象拷贝,而不必为每次使用都创建新的对象,好处:
1> 被享元模式维护的相同对象每次只会被创建一次,当创建的对象比较耗时时,便可以节省大量时间
2> 创建对象减少,内存的需求也会减少,使得GC的压力也响应降低
应用:String类对象,Java中将String类定义为final(不可改变的),JVM中字符串一般保存在字符串常量池中,java会确保一个字符串在常量池中只有一个拷贝,这个字符串常量池在JDK6.0以前是位于常量池中,位于永久代,而在JDK7.0中,JVM将其从永久代拿出来放置于堆中
观察者模式
当一个对象的行为依赖于另外一个对象的状态时,观察者模式就相当有用,如果不使用观察者模式,则只能在另一个线程中不停的监听对象所依赖的状态。可能需要开很多线程来实现这个功能
常用优化组件和方法
1、缓冲
缓冲区可以是一块特定的区域,主要是为了解决应用程序上下层之间的性能差异,提高系统的性能。使用场景特点:
1> 数据通信不需要太实时,异步通信
应用:消息队列MQ,起到削峰填谷的功能。日志系统silfj,数据太大就先写入队列,慢慢写入日志服务器
2、缓存
作用:开辟一块内存空间存放数据处理结果,供下次访问使用。
应用:Redis等缓存软件功能
3、对象复用(池化)
如果一个类被频繁请求使用,那么不必每次都生成一个实例,可以将这个类的一些实例保存在一个池中,待需要使用时从池中获取,用完了再放回池中。
应用:线程池和数据库的连接池都是使用了该方法
4、并行代替串行
结合CPU的多核并行能力,开启多线程发挥CPU的最大潜能
5、负载均衡
应用:分布式集群
Java程序优化
有助于提升性能的技巧
1、慎用异常
try-catch实现:每个类class文件会跟随一张异常表,每一个try-catch都会在这个表里添加行记录,每一个记录都有4个信息(try catch的开始行(begin_pc),结束行(begin_pc),异常的处理起始行(handler_pc,catch代码块),异常类型catch_type)
1> 代码发生异常时,就会去异常表中找抛出异常的行是否在begin_pc和begin_end之间,如果是的话,并且是catch_type类型,则跳转到handler_pc的位置去执行。停止方法的出栈、入栈操作,回溯出整个链路的栈信息
2> 如果代码不发生异常,则不会去表中查找,基本上不会有性能消耗
建议:需要try-catch的地方还是需要继续用。避免在for循环中使用
2、使用局部变量
调用方法时传参以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,静态变量,实例变量等,都在堆(Heap)中创建,速度较慢
3、位运算代替乘除法
所有运算中,位运算是最高效的
a*=2 ==> a<<=1
a/=2 ==> a>>=1
4、尽可能的提取表达式,避免多余的计算
x = d a b / 3 4 a;
y = e a b / 3 4 a;
可以优化为
t = a b / 3 4 * a;
x = d * t;
y = e * t;
5、静态方法替代实例方法
java中实例方法需要维护一张类似虚函数表的结构,以实现对多态的支持。与静态方法相比,实例方法的调用需要更多的资源(比如如果它继承了父类的话,实例化对象时可能需要执行父类的构造方法)