Java性能调优续
Java性能调优续
3.2 字符串的调优
下面列出一些常见的关于字符串优化的策略,简单的我就不多作解释了。
1) 使用规则表达式处理字符串匹配代替复杂的字符串查找和复制操作;
2) 使用不拷贝字符串中字符的高效方法,例如String.subString()方法;
3) 尽可能不要使用需要拷贝字符串中字符的低效方法,例如String.toUpperCase()和String.toLowercase();
4) 在编译期使用String的“+”操作符来执行连接操作,在运行期使用StringBuffer执行连接操作;
这里特别强调一下,因为我已经在网上看到好多文章都推荐使用StringBuffer的append()方法来做字符串的连接操作。其实在JVM能够在编译期就能确定结果的情形,使用String的“+”操作符的性能要好很多。
3.3 异常,类型转换和变量
1) 考虑在抛出异常的时候是否可以不即时生成堆栈信息而使用一个已有的异常实例;
创建异常的开销很大。当创建一个异常时,需要收集一个栈跟踪(Stack Trace),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。运行时栈不是为有效的异常创建 而设计的,而是设计用来让运行时尽可能快地运行。入栈,出栈,入栈,出栈。让这样的工作顺利完成,而没有任何不必要的延迟。但是,当需要创建一个 Exception时,JVM不得不说:“先别动,我想就你现在的样子存一份快照,所以按时停止入栈和出栈操作,笑着等我拍完快照吧。”栈跟踪不只包含运 行时栈中的一两个元素,而是包含这个栈中的每一个元素,从栈顶到栈底,还有行号和一切应有的东西。
因此,创建异常这一部分开销很大。从技术上讲,栈跟踪快照是在本地方法Throwable.fillInStackTrace()中发生的,这个方法不是 从Throwable contructor那里调用的。但是这并并没有什么影响——如果你创建了一个Exception,就得付出代价。好在捕获异常开销不大,因此可以用 try-catch将核心内容包起来。你也可以在方法定义中定义throws子句,这样对性能不会造成什么损失。从技术上讲,你甚至可以随意地抛出异常, 而不用花费很大的代价。招致性能损失的并不是throw操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。
幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。但是,万一你不想遵从好的编程习惯,Java语言就会让你知道,那样就可以让你的程序运行的更快,从而鼓励你去那样做。
2) 用instanceof替代在try-catch中做投机的强制类型转换方法;
3) 尽可能少的使用强制类型转换方法,尤其是使用类型特定的集合类时;
4) 使用int优先于其他所有的数据类型;
5) 尽可能使用基本数据类型做临时变量;
6) 考虑直接获取实例变量而不通过get,set方法获取(注意:这不符合面向对象的封装原则,不推荐使用)。
3.4 循环,选择和递归
1) 在循环中消除不必要的代码,做尽可能少的事情;
2) Switch语句中使用连续的case值;
3) 确定是否真的需要用到递归,最好转为用循环来实现。
3.5 输入输出操作
1) 在程序中尽量不要使用System.out这样的语句,而使用log4j这样的日志工具替换,以在程序正式上线的时候可以关闭所有不必要的日志操作提高性能;
2) 当程序中有大量的I/O操作时,考虑将日志写入不同的文件做到并行化操作以提高性能,并可以用一个后台线程执行I/O操作而不打断正常程序的执行;
3) 正确的使用序列化机制,没有必要序列化的成员变量需要标识为transient;
4) 使用NIO技术。
3.6 JDBC
1) 使用正确的JDBC驱动,尽可能地选择最新的JDBC驱动;
最新的JDBC驱动不仅优化了性能,而且提供了更多的性能更好的接口供开发人员使用。
2) 使用应用服务器自带的连接池,而不要使用自己的连接池或干脆不用连接池;
3) 在使用完数据库资源后,需依次关闭ResultSet,Statement和Connection;
4) 手动控制事务,使用connection.setAutoCommit(false)关闭自动提交,使用executeBatch()进行批量更新;
5) 业务复杂或者大数据量操作时使用存储过程;
6) ResultSet.next()极其消耗性能,建议使用RowSet替代ResultSet;
7) 把所有的字符数据都保存为Unicode,Java以UniCode形式处理所有数据,数据库驱动程序不必再执行转换过程;
8) 尽可能的优化SQL语句;
9) 少用join,多用index;
10) 使用EXPLAIN工具监控SQL语句的执行,以确定瓶颈所在;
11) 不要使用 SELECT * ..., 使用 SELECT Field1, Field1 ...;
12) 通过index获取字段,而不要使用名字去获取,例如resultSet.getString(1) 而不是 resultSet.getString("field1");
13) 缓存数据,避免重复查询;
14) 考虑使用内存数据库;
15) 调整fetch size进行批量查询;
16) 尽可能的使Java数据类型和数据库类型相匹配,转换数据在匹配不好的数据类型间效率太差;
17) 避免使用低效的metadata调用,尤其是getBestRowIdentifier( ), getColumns( ), getCrossReference( ), getExportedKeys( ), getImportedKeys( ), getPrimaryKeys( ), getTables( ), and getVersionColumns( );
18) 使用metadata查询减少数据库网络通信量;
19) 使用最低的事务隔离级别;
20) 使用乐观锁机制;
21) 把应用服务器和数据库分散在不同的机器中,性能可能会更好。
3.7 Servlet和JSP
1) Session的使用;
应用服务器保存很多会话时,容易造成内存不足,所以尽量减少Session的使用,放置到Session中的对象不应该是大对象,最好是简单的小对象,实 现串行化接口。当会话不再需要时,应当及时调用invalidate()方法清除会话。而当某个变量不需要时,及时调用 removeAttribute()方法清除变量。当session终止时需要清除不必要的资源,实现 HttpSessionBindingListener接口的valueUnbound()方法。
2) 使用include directive,而不使用include action;
目前在JSP页面中引入外部资源的方法主要有两种:include directive和include action。Include directive:例如<%@ include file=”copyright.html” %>,该指令在编译时引入指定的资源。在编译之前,带有include指令的页面和指定的资源被合并成一个文件。被引用的资源在编译时就确定,比运 行时才确定资源更高效。Include action:例如< jsp:include page=”copyright.jsp” />,该动作引入指定页面执行后生成的结果。由于它在运行时完成,因此对输出结果的控制更加灵活。但是,只有当引用的内容被频繁改变时,或者在对主 页面的请求没有出现之前,被引用的页面无法确定时,使用include action才合算。
3) 对于那些无需跟踪会话状态的jsp,关闭自动创建的会话可以节省一些资源。使用如下page指令: < %@ page session=”false” %>;
4) 尽量不要把jsp页面定义为单线程,应设置为< %@page isThreadSafe=”true” %>;
5) 在jsp页面最好使用输出缓存功能,如:< %@page buffer=”32kb” %>;
6) 在servlet之间跳转时,forward比sendRedirect更有效;
7) 设置HttpServletResponse缓冲区,如:response.setBufferSize(20000);
8) 建议在servlet里使用ServletOutputStream输出图片等对象;
9) 不要使用SingleThreadModel,使Servlet是线程安全的,但是尽可能的减少消耗在同步代码上的时间,使用足够多的servlet去响应用户的请求;
10) 尽可能的使useBean的范围在page范围内;
11) Servlet的inti()和destroy()或jspInit()和jspDestroy()方法用于创建和删除昂贵的资源,例如缓存对象和数据库连接;
12) 避免使用反向DNS查找;
13) 预编译JSP页面;
14) 尽可能的在客户段校验数据;
15) 禁止自动装载特色防止周期性的装载servlet和jsp。
3.8 EJB
由于EJB2.0已经很少项目在用了,EJB3.0再成熟一点,我再补充这一部分吧!
已有 0 人发表留言,猛击->> 这里<<-参与讨论
ITeye推荐