`

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics