张:
如何使用Exception
Exception降低性能。一个异常抛出首先需要创建一个新的对象。Throwable接口中的构造器调用名为fillInStackTrace()的本地方法。这个方法负责巡检栈的整个框架来收集跟踪信息。这样无论何时有异常抛出,它要求虚拟机装载调用栈,因为一个新的对象在中部被创建。
异常应当仅用于有错误发生时,而不要控制流。
我有机会在一个专门用于无线内容市场的网站(名字故意隐去了)看到一段代码,其中开发者完全可以使用一个简单的对照来查看对象是否为空。相反,他或她跳过了这个检查而实际上抛出Null-PointerException。
对于很多Exception或者Error都不是像普通Java对象那样新建的.所以最好别自创异常,或者减少自创的异常种类数量, 另外也应该减少异常的继承树的大小,因为异常出现后JVM需要在异常表查找下一个跳转点,过多的种类会拖累性能.
在任何可能的地方让类为Final
标记为final的类不能被扩展。在《核心Java API》中有大量这个技术的例子,诸如java.lang.String。将String类标记为final阻止了开发者创建他们自己实现的长度方法。
更深入点说,如果类是final的,所有类的方法也是final的。Java编译器可能会内联所有的方法(这依赖于编译器的实现)。在我的测试里,我已经看到性能平均增加了50%。
停止小聪明
很多开发人员在脑子中编写可复用和灵活的代码,而有时候在他们的程序中就产生额外的开销。曾经或者另外的时候他们编写了类似这样的代码:
public v oid doSomething(File file) {
FileInputStream fileIn = new FileInputStream(file);
// do something
他够灵活,但是同时他们也产生了更多的开销。这个主意背后做的事情是操纵一个InputStream,而不是一个文件,因此它应该重写如下:
public void doSomething(InputStream inputStream){
// do something
选择一个基于垃圾收集实现的虚拟机
许多人可能会对Java规范不需要实现垃圾收集感到惊讶。设想时代已经是我们都拥有无限内存计算机。总之,垃圾收集器日常事务就是负责发现和抛出(hence garbage)不再需要的对象。垃圾收集必须发现那些对象不再被程序指向,并且使被对象占用的栈内存被释放掉。它还负责运行任何被释放对象的finalizer。
垃圾收集故意不允许你释放并非由你分配的内存,从而帮助你确保程序完整,当JVM确定CPU时间的时间表并且当垃圾收集器运行时,这个进程也产生开销。
垃圾收集器有两个不同的步骤执行他们的工作。
实现了定位计算的垃圾收集器在栈中为每一个对象保留一个计数。当一个对象被创建并且对它的一个定位被分配给一个变量,计数增加。当对象越出范围,定位计数被设置成0并且对象可以被垃圾收集。这个步骤允许参考计数器运行在与程序执行有关的短时间增量内。定位计数在父子彼此拥有定位的应用里运行不正常。每次一个对象刷新时也会有定位计数增加和减少的开销。
何:
对于一般的中小型系统,性能瓶颈往往不在于(*如何使用Exception* 、*不要两次初始化变量* 、*对新的关键词使用优选法则* 、*乘法和
除法* ),而在于不完备的业务逻辑,或者是没有采用好的算法处理数据。
对于系统调优,最好先从整体着手,对(数据库负载、网络负载、系统负载等)情况进行监控,然后将量化后的结果进行分析,具体问题具体处理。
例子(数据库负载过高):
当发现系统在数据库耗时太长时,可以先观察一下数据库,看看是由于对同一张表更新太频繁,导致锁表的时间太长。还是由于数据量大,导致查询时的全表扫描
比较耗时。
如果是前者,那么可以考虑对数据进行分区,减少更新时的冲突。
如果是后者,可以考虑对数据表加索引(太多的索引反而会降低性能)、改变查询条件、对原有的SQL进行优化,加上必要的hint等。
好的代码不一定是执行最快的代码,但一定是最清晰易懂的代码。
除法* ),而在于不完备的业务逻辑,或者是没有采用好的算法处理数据。
对于系统调优,最好先从整体着手,对(数据库负载、网络负载、系统负载等)情况进行监控,然后将量化后的结果进行分析,具体问题具体处理。
例子(数据库负载过高):
当发现系统在数据库耗时太长时,可以先观察一下数据库,看看是由于对同一张表更新太频繁,导致锁表的时间太长。还是由于数据量大,导致查询时的全表扫描
比较耗时。
如果是前者,那么可以考虑对数据进行分区,减少更新时的冲突。
如果是后者,可以考虑对数据表加索引(太多的索引反而会降低性能)、改变查询条件、对原有的SQL进行优化,加上必要的hint等。
好的代码不一定是执行最快的代码,但一定是最清晰易懂的代码。