一、一般来说,程序的性能通过以下几个方面来表现:
1、执行速度: 程序的反映是否迅速,响应时间是否足够短
2、内存分配: 内存分配是否合理,是否过多地消耗内存或者存在泄漏
3、启动时间: 程序从运行到可以正常处理业务需要花费多长时间
4、负载承受能力: 当系统压力上升时,系统的执行速度、响应时间的上升曲线是否平缓
性能参考指标包括:
1、执行时间: 一段代码从开始运行到运行结束,所使用的时间
2、CPU时间: 函数或者线程占用CPU的时间
3、内存分配: 程序在运行时占用的内存空间
4、磁盘吞吐量: 描述I/O的使用情况
5、网络吞吐量: 描述网络的使用情况
6、响应时间: 系统对某用户行为或者事件做出响应的时间。响应时间越短,性能越好。
木桶原理的概念: 系统的最终性能取决于系统中性能表现最差的组件。需要着重平衡系统中各组件的整体性能,必须对系统中表现最差的组件进行优化。
除了以上的指标可能产生影响外,还有例如 异常的捕获和处理、海量数据的读写操作,激烈的锁竞争等。
** 尽量降低程序中串行化的比重,增加并行化模块的比重,充分利用多核CPU资源有利于提高系统的性能
二、性能调优层次
1、设计调优: 从某种程度上说,设计优化直接决定了系统的整体品质。设计人员必须熟悉常用的软件设计方法、设计模式、基本性能组件和常用优化思想。
2、代码调优: 例如LinkedList和ArrayList在随机访问上的性能的巨大差别;又如文件读写Stream和JAVA NIO之间的差别。
3、JVM调优: 依据应用程序的特点,设置合理的JVM启动参数,选用合理的垃圾回收策略等。
4、数据库调优:
1)应用层优化: 比如显示指定列名,避免使用星号"*"。
2)数据库优化: 比如提高多表级联查询效率,合理使用冗余字段;大表的行水平切割;提高数据库查询效率,建立有效且合理的索引。
5、操作系统调优: 比如在主流UNIX系统中,共享内存段、信号量、共享内存最大值、共享内存最小值等都是可以进行优化的系统资源。此外,如最大文件句柄数、虚拟内存大小、磁盘的块大小等参数都可能对软件性能产生影响。
系统性能优化的最主要目的: 就是查找并解决性能瓶颈问题。
步骤: 确立性能目标--测试--是否达到预期目标--如果没有则查找瓶颈--通过一些手段进行改进实现(此手段可参考上述调优层次介绍,甚至可以更新硬件)。
** 性能调优必须有明确的目标,不要为了调优而调优,如果当前程序并没有明显的性能问题,盲目地进行调整,其风险可能远远大于收益。
关于设计优化:
设计模式 是前人工作的总结和提炼。某种设计模式都是对某一特定问题的成熟的解决方案。合理的应用,不仅能使系统更容易被他人理解,同时也能使系统拥有更加合理的结构。 (关于设计模式的具体系统应用,可看本博客的部分其他文章,已针对部分设计模式进行了实际业务场景应用)
1、单例模式: 一种对象创建模式,用于产生一个对象具体实例,可以确保系统中一个类只产生一个实例。
---- 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。
---- 由于new操作的次数减少,因而对系统内存的使用频率也会降低,将减轻GC压力,缩短GC停顿时间。
** 注意懒汉式与饿汉式的区别;注意在多线程情况下可能导致的多实例的问题
** 使用内部类的方式实现单例,既可以做到延迟加载,也不必使用同步关键字,是一种比较完善的实现。
2、代理模式: 使用代理对象完成用户请求,屏蔽用户对真实对象的访问。
代理模式可以用于多种场合,如用于远程调用的网络代理、考虑安全因素的安全代理等。延迟加载只是代理模式的一种应用场景。
public interface IDBQuery{ String request(); }
public class DBQuery implements IDBQuery { public DBQuery(){ try { //可能包含一些耗时操作 Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); } } @Override public String request() { return "requesnt string"; } }
public class DBQueryProxy implements IDBQuery{ private DBQuery real = null; @Override public String request() { if(real == null){ //在真正需要的时候,才创建真实对象,创建过程可能很慢 real = new DBQuery(); } return real.request(); } }
动态代理: 使用字节码动态生成加载技术[并加载到当前的ClassLoader],在运行时生成并加载类。优势: 1 不需要为真实主题写一个完全一样的封装类,一个是可能方法很多;另一个是如果接口有变动则都要修改。 2 使用一些动态代理的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性
3、享元模式
4、装饰者模式
5、观察者模式
常用优化方法:
缓冲: 可以协调上层组件和下层组件的性能差。当上层组件性能优于下层组件时,可以有效减少上层组件对下层组件的等待时间。【比如内存向硬盘中写数据】
由于I/O操作很容易成为性能瓶颈,所以,尽可能在I/O读写中加入缓冲组件,以提高系统的性能
缓存: 可以保存一些来之不易的数据或者计算结果。当需要再次使用这些数据时,可以从缓存中低成本地获取,而不需要再占用宝贵的系统资源。
最为简单的缓存可以直接使用HashMap实现。当然,这样做会遇到 很多问题,例如何时应该清理无效的数据,如何防止缓存数据过多而 导致内存溢出等。一个稍好的替代方案是直接使用WeakHashMap,它使 用弱引用维护一张哈希表,从而避免潜在的内存溢出问题,但是作为 专业的缓存,它的功能也略有不足。
对象池化: 如果一个类被频繁地请求使用,那么不必每次都生成一个实例,而将这个类的实例保存在一个池中,待需要使用的时候直接从池中获取。这个池就被称为对象池。
线程池: 由于线程的创建和销毁是较为费时的操作,因此在线程调度频繁的系统中,线程池可以很好地改善性能。
数据库连接池: 由于数据库连接的创建和销毁是重量级的操作,因此避免频繁地进行这两种操作,对改善系统的性能也有积极意义。
Jakarta Commons Pool对象池组件,可以直接使用。
在Jakarta Commons Pool中已经内置了3个对象池,分别是 StackObjectPool、Generic-ObjectPool和 SoftReferenceObjectPool。
** 只有对重量级的对象使用对象池技术才能提高系统的性 能;对于轻量级的对象使用对象池,反而可能会降低系统的性能
Java中提供了Thread对象和Runnable接口用于创建进程内的线程。其 次,为了优化并行程序的性能,JDK还提供了java.util.concurrent并 发包,内置各种多线程性能优化工具和组件,如线程池、各种并发数 据结构等。除此之外,为确保多线程间能相互协作,JDK还提供了各种 同步工具。
性能优化的关键在于掌握各部分组件的性能平衡点。如 果系统CPU资源有空闲,但是内存使用紧张,便可以考虑使用时间换 空间的策略,以达到整体性能的改良。反之,CPU资源紧张,而内存 资源有空闲,则可以使用空间换时间的策略,从而提升整体性能。