首页 » Java程序员修炼之道 » Java程序员修炼之道全文在线阅读

《Java程序员修炼之道》分布式网络计时

关灯直达底部

我们对性能调优的大部分讨论都是以单机上的系统为中心的。但你应该知道,当涉及网络上的系统调优时,会有一些特别的问题。网络上的同步和计时并不容易,而且不仅仅是在互联网上,即便是以太网也会出现这些问题。

详细讲解分布式网络计时超出了本书的范围,但你应该知道,通常来说,很难得到用于跨越几台机器的工作流的准确时序。另外,即便NTP这样的标准协议对于高精度工作来说准确度也不够。

在开始讨论垃圾收集之前,我们先看一个前面提到过的例子——缓存对代码性能的影响。

6.4.4 案例研究:理解缓存未命中

对于很多吞吐量较高的代码来说,影响性能的一个主要因素就是一级缓存未命中的数量。

代码清单6-2中的代码操作1MB的数组,并输出执行两个循环中之一所用的时间。在第一个循环中,每隔16个条目对int数组中的元素加1。一级缓存的一个缓存行中通常有64个字节(在32位JVM上,Java的int是4个字节),所以这意味着每次会读取一个缓存行(64=16*4)。

代码清单6-2 理解缓存未命中

public class CacheTester {  private final int ARR_SIZE = 1 * 1024 * 1024;  private final int arr = new int[ARR_SIZE];  private void doLoop2 {      for (int i=0; i<arr.length; i++) arr[i]++; //处理每个条目  }  private void doLoop1 {      for (int i=0; i<arr.length; i += 16) arr[i]++;//处理每个缓存行  }  private void run {      for (int i=0; i<10000; i++) {//代码热身        doLoop1;        doLoop2;        }      for (int i=0; i<100; i++) {        long t0 = System.nanoTime;        doLoop1;        long t1 = System.nanoTime;        doLoop2;        long t2 = System.nanoTime;        long el = t1 - t0;        long el2 = t2 - t1;        System.out.println("Loop1: "+ el +" nanos ; Loop2: "+ el2);        }    }    public static void main(String args) {      CacheTester ct = new CacheTester;      ct.run;    }}  

注意,在你得到准确结果之前应该让代码热热身,以便让JVM对你感兴趣的方法进行编译。我们会在6.6节讨论更多与代码热身相关的内容。

第二个循环,doLoop2给数组中的每个元素加1,所以看起来它做的工作是doLoop1的16倍。下面是在笔记本上运行这段代码得到的结果:

Loop1: 634000 nanos ; Loop2: 868000Loop1: 801000 nanos ; Loop2: 952000Loop1: 676000 nanos ; Loop2: 930000Loop1: 762000 nanos ; Loop2: 869000Loop1: 706000 nanos ; Loop2: 798000  

计时子系统的疑难杂症

结果中的所有纳秒值都很整齐,全是一千的整数倍。这表明底层系统调用(System.nanoTime最终所调用的)仅仅返回了一个微秒整数值——一微秒是1000纳秒。因为这个结果是在Mac笔记本上得到的,所以我们猜测在OS X的底层系统调用只有微秒级的精度,实际上,它调用的是gettimeofday

从这个结果来看,doLoop2所用的时长不是doLoop1的16倍。这表明内存访问在总体性能配置中占有支配性地位。doLoop1doLoop2读取缓存行的次数相同,而修改数据所用的CPU周期只占整体时间的一小部分。

我们先来回顾下Java时间系统的要点。

  • 大多数系统内部都有几个不同的时钟。
  • 毫秒计时器是安全可靠的。
  • 更高精度的时间需要仔细处理以防止出现偏离。
  • 你需要知道计时测量的精确度和准确度。

我们下一个将要讨论的是Java平台的垃圾收集子系统。这是性能的决定性因素中非常重要的一部分,并且它有很多可调节的部分,对于做性能分析的开发人员来说都可以成为非常重要的工具。