提升你的Java应用性能:改善数据处理
编者注:本文为历史博文归档;涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效,阅读时请注意时效性。
翻译自 deepakgaikwad。如需转载本文,请先参见文章末尾处的转载要求。
许多应用程序在压力测试阶段或生产环境中往往会遭遇性能瓶颈。深入分析性能问题的根源,会发现很多是由数据处理不当造成的。尤其在面对大数据量场景时,数据处理方式至关重要。以下是一些实用的数据处理技巧,有助于显著提升 Java 应用程序的性能。
减少数据传输
在任何 Java 应用程序中,方法调用要么是为调用方完成某项任务,要么是对输入数据进行处理。这两个目标都需要在调用者和处理方法之间进行数据交换。关于最小化方法输入输出数据量,有一条经验法则:传输的数据越少越好。例如,数据量越小,处理开销越低,需要清理的对象越少,内存占用也更少。程序设计应当努力减少不同方法、层次和应用程序之间,甚至组织之间的数据传递。通过下文将要讨论的“源端数据处理”策略可以达成这个目标。
延迟加载
延迟加载(Lazy Loading)是指直到实际需要数据的最后一刻才从数据存储中获取数据。在面对重量级对象时,这一策略非常有益。例如,有一个存储在数据库中的文件实体,该文件包含 Blob 数据以及其他属性。Blob 的大小可以从几 KB 到几十兆不等,而中间层逻辑在显示文件内容之前通常只依赖于其他属性。此时,可以使用延迟加载来处理这个 Blob 属性,避免不必要的加载开销。
避免重复数据调用
当进行远程调用时,反复从数据提供者处获取数据会严重影响性能,例如数据库调用、Web 服务调用或者其他编解码调用。这种情况下,可以使用 Facade(外观)模式一次获得所有所需的数据,尽可能减小连接成本和在网络上传输数据的成本。
高速缓冲
经常使用但不经常变化的数据可以进行缓存,通常需要缓存的是静态数据或者服务端数据。如今,对应用事务数据也有很高的性能要求,这些数据也需要加入缓存。作为一个简单的规则,在设计应用程序时需要识别这类实体并缓存到合适的位置,通常这些实体不会频繁改变甚至根本不会变化。刷新对象时也可以采用这个规则。
在源端处理数据
在数据源或存储位置本身进行处理是一个好习惯。将大量数据发送给客户端然后再进行处理不仅需要传输成本,而且有时客户端的处理逻辑会改变数据格式。例如在 Oracle 数据库中过滤数据比较简单,只要为查询添加一个 WHERE 子句即可。而在 Java 程序中过滤这些数据,需要先获取记录再逐行挨个属性进行比较。因此,用 Java 进行过滤可能不是最佳实现。
减少数据转换与避免类型误用
将数据从一种格式转换到其他格式需要付出转换成本。对单个值进行转换消耗的性能可能微不足道,但如果记录个数成千上万,性能问题就十分明显。例如,选择 String 数据类型的值,并把它转换为 double 或其他基本类型,反之亦然,都应尽量避免不必要的转换。
选择合适的集合类型
从性能的角度来看,这是一个非常重要的考虑因素。Java 提供了不同的集合以满足不同的需求。例如有几种基础的集合,比如 ArrayList,你可以不断向 ArrayList 添加数据并且集合本身不会对数据进行任何同步操作。再比如 Vector 提供了同步的操作。我需要在插入数据时保持同步吗?这是一个很好的问题。如果不需要同步,那么就不要使用 Vector,使用 ArrayList 或根据要求选择其他集合。
优化数据处理算法
有时候性能问题是数据处理算法或实现逻辑造成的。实现逻辑应该将性能作为要求达到的一个目标,像是内存占用等。通过以下几个方法可以使算法进一步优化:
- 优化开销很大的调用和数据库循环调用
- 优化循环里的对象声明
- 避免不必要的嵌套循环
- 将对象存储到多个集合
重型数据对象的生命周期管理
我们不能保证会立即执行垃圾收集(Garbage Collection),但是将对象引用置为 null 是一个很好的做法,有助于垃圾回收器更早地回收内存。
利用技术特性优化
许多技术都有助于数据处理,其中包含了上面提到的一些要点。下面是几个例子:
- Oracle 的
PreparedStatement - 缓存框架,例如 Hibernate 的一级缓存和二级缓存
- Hibernate 框架的延迟加载机制
数据序列化与反序列化
在设计时需要避免性能代价过高的操作。如果没有这样的操作,还可以把数据转换减到最小。例如在 Web 应用程序中,可以尽量减少会话(Session)的输出数据。
并行处理数据
如果需要处理的数据量很大,那么可以并行处理不相关的数据以减少总的处理时间。
对象重用
对于重量级对象不要从头创建,可以对现有对象进行克隆并且只修改必要的属性,尽可能重用现有的信息。通过浅拷贝和深拷贝来控制重用的数量。
说明:本文部分建议(如finalize机制、Vector的使用等)基于较早的 Java 版本实践。在现代 JDK 版本中,finalize方法已被 deprecated 甚至移除,建议优先使用try-with-resources或Cleaner机制管理资源;集合类请优先根据并发需求选择ArrayList或并发包下的集合类。具体实现请以当前官方文档为准。
版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/ti-sheng-ni-de-java-ying-yong-xing-neng--gai-shan-shu-ju-chu-li.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。
