学习
实践
活动
专区
工具
TVP
写文章

Java性能权威指南:性能测试方法

2.1 原则1:测试真实应用

应该在产品实际使用的环境中进行性能测试,这样测试出的数据才有参考意义。

2.1.1 微基准测试

第 1 种是微基准测试。微基准测试用来测量微小代码单元的性能,包括调用同步方法的用 时与非同步方法的用时比较,创建线程的代价与使用线程池的代价,执行某种算法的耗时 与其替代实现的耗时,等等。

微基准测试看起来很好,但要写对却很困难。考虑以下代码,被测的方法是计算出第 50个斐波那契数,这段代码试图用微基准测试来测试不同实现的性能:

public void doTest() { // 主循环

double l; long then = System.currentTimeMillis(); for (int i = 0; i

l = fibImpl1(50); }

} ... private double fibImpl1(int n) {

if (n 0"); if (n == 0) return 0d; if (n == 1) return 1d; double d = fibImpl1(n - 2) + fibImpl(n - 1);

if (Double.isInfinite(d)) throw new ArithmeticException("Overflow");

return d; }

这段代码的最大问题是,实际上它永远都不会改变程序的任何状态。因为斐波那契的计算

结果从来没有被使用,所以编译器可以很放心地去除计算结果。智能的编译器(包括当前

的 这段代码的最大问题是, Java 7 和 Java 8)最终执行的是以下代码:

long then = System.currentTimeMillis();

long now = System.currentTimeMillis();

结果是,无论计算斐波那契的方法如何实现,循环执行了多少次,实际的流逝时间其实只 有几毫秒。循环如何被消除的细节请参见第 4 章。

微基准测试几要素

1. 必须使用被测的结果

2. 不要包括无关的操作

3. 必须输入合理的参数

综合所有因素,正确的微基准测试代码看起来应该是这样:

package net.sdo;

import java.util.Random;

public class FibonacciTest {

private volatile double l;

private int nLoops;

private int[] input;

public static void main(String[] args) {

FibonacciTest ft = new FibonacciTest(Integer.parseInt(args[0]));

ft.doTest(true);

ft.doTest(false);

}

private FibonacciTest(int n) {

nLoops = n;

input = new int[nLoops];

Random r = new Random();

for (int i = 0; i

input[i] = r.nextInt(100);

}

}

private void doTest(boolean isWarmup) {

long then = System.currentTimeMillis();

for (int i = 0; i

l = fibImpl1(input[i]);

}

if (!isWarmup) {

long now = System.currentTimeMillis();

} }

private double fibImpl1(int n) {

if (n 0");

if (n == 0) return 0d;

if (n == 1) return 1d;

double d = fibImpl1(n - 2) + fibImpl(n - 1);

if (Double.isInfinite(d)) throw new ArithmeticException("Overflow");

return d;

}

}

2.1.2 宏基准测试

衡量应用性能最好的事物就是应用自身,以及它所用到的外部资源。如果正常情况下应用 需要调用 LDAP 来检验用户凭证,那应用就应该在这种模式下测试。虽然删空 LDAP 调用 在模块测试中有一定意义,但应用本身必须在完整真实配置的环境中测试。

随着应用规模的增长,上述准则愈加重要也更难达到。复杂系统并不是各个部分的简单加 和,装配之后,各部分的行为会有很大不同。所以,比如你伪装数据库调用,那就意味着 你并不担心数据库的性能——对了,你是 Java 人,为什么要处理其他人的性能问题呢?数 据库连接会因为缓存而消耗大量堆内存,网络也会因为发送大量数据而饱和,代码调用简 单方法(与调用 JDBC 驱动程序的代码相比)时的不同优化,短代码路径因为 CPU 管线和 缓存而比长代码路径更为有效,等等。

2.1.3 介基准测试

我的调优工作包括Java SE和EE,每种都会有一组类似微基准测试的测试。对于Java SE工程师来说,这个术语意思是样本甚至比2.1.1节的还要小:测量很小的东西。Java EE工 程师则将这个术语用于其他地方:测量某方面性能的基准测试,但仍然要执行大量代码。

Java EE微基准测试的例子,测量从应用服务器返回的简单JSP响应。仔细比较处理请求 的代码和传统微基准测试的代码:有许多 socket 管理代码,读取请求、查找(可能需要编 译)JSP、写入响应等代码。从传统角度来看,这不能算微基准测试。

这种测试也不是宏基准测试:没有安全(比如用户不用登录),没有会话管理,也没有大 量使用其他的Java EE特性。因为它只是实际应用的子集,介于两者之间——它是介基准 测试。介基准测试并不局限于Java EE:它是一个术语,我用来表示做一些实际工作,但 不是完整应用的基准测试。

《Java性能权威指南》文字版PDF下载,关注:java技艺,回复:Java性能权威指南

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180622G1WAPP00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券