这篇文章上次修改于 2136 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

1.java性能调优面临的问题

  • 能运行大内存堆的机器越来越多。催生了大内存堆的垃圾回收器G1
  • 云计算又提升了单CPU和小内存的能力,这个时候又需要针对小内存和单CPU进行优化
    2.java性能调优包含的领域
  • 调整tuning flags ——编译器和垃圾收集器等。
  • API的最佳实践
    3.JVM tuning flags 调优参数
  • Boolean类型:-XX:+FlagName表示启用,-xx:-FlagName表示禁用。
  • key value类型:-XX:FlagName=Param,一般Param是任意值。
  • 使用-XX:+PrintFlagsFinal 打印当前环境下所有flag的默认值。
  • 这些基于环境自动优化的过程称为ergonomics(自动优化).自动优化的前提——JVM会把机器识别为Client类或者Server类。32位的windows不考虑CPU核数,直接判定为Client类。32位的+单核的话。也是判定为Client类,不考虑操作系统。其他都认为是Server类。
    4.JVM调优的瓶颈—-数据库。
  • 有时候JVM调优后负载可以上升,但是数据库是瓶颈,JVM性能好反而导致数据库性能进一步下降。这样会得出一个错误的结论:JVM性能越好,整体性能反而更糟。
  • 所以负载能力和响应时间有时候需要权衡。如CPU密集型,增加线程数,等待锁的时间增加,上下文切换增加,延时增加。
    5.性能条有的常见手段。
  • 借助性能分析,来优化代码。重点关注性能分析中最耗时的操作。但是这个不意味着只看叶子方法(请把调用链路看成一棵树)
  • 使用奥卡姆剃刀原理()分析性能问题。新代码比机器配置更可能引起性能问题。机器配置比JVM或者操作系统的bug更容易引起性能问题。即——最可能的原因往往最容易解释。不要一上来就跳到不太可能的场景。
  • 为最常用的操作,编写简单的算法。
    ——————————————————-性能测试的方法————————-
    1.原则1—-测试真实的应用,应该在产品实际的使用环境中进行测试
  • 微基准测试microbenchmarks,微小代码单元的测试。但是要注意两个计时之间的代码是否被使用过,如下面的代码
    public void doTest() {
    // Main Loop
    double l;
    long then = System.currentTimeMillis();
    11
    www.it-ebooks.infofor (int i = 0; i < nLoops; i++) {
    l = fibImpl1(50);
    }
    long now = System.currentTimeMillis();
    System.out.println("Elapsed time: " + (now - then));
    }
    ...
    private double fibImpl1(int n) {
    if (n < 0) throw new IllegalArgumentException("Must be > 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;
    }
    
    由于斐波那契的结果没被使用,智能编译器会优化成如下代码
    long then = System.currentTimeMillis();
    long now = System.currentTimeMillis();
    System.out.println("Elapsed time: " + (now - then));
    
    那么会得到错误的结果为几毫秒。
    解决办法是—-把l提升为实例变量,并且标记为volatile(强制每次写以后有一次的同步刷新—-实际使用了cpu栅栏)
    即确保读取被测试的结果,而不是i简单的写入
    +不要包括无关的操作
  • 必须输入正确的参数,提前预知参数的正确性,而不是等运行出错了才知道.这个和我们常说的快速失败很像。
    ```java
    public double fibImplSlow(int n) {
    if (n < 0) throw new IllegalArgumentException(“Must be > 0”);
    if (n > 1476) throw new ArithmeticException(“Must be < 1476”);
    return verySlowImpl(n);
    }

```

  • 热点代码比较快,就是一段代码执行的越多,他的速度就越快
    2.宏基准测试MacroBenchmarks
  • 必要性,JVM共用cpu的时候,GC效率不一样
    3.Mesobenchmarks 介基准测试