Java 性能调优学习笔记 001

 

JVM 调优标志

除了少数例外,JVM 主要接受两类标志:布尔标志和附带参数的标志。

布尔标志采用以下语法: -XX:+FlagName 表示开启,-XX:-FlagName 表示关闭。

附带参数的标志采用以下语法: -XX:FlagName=something 表示将标志 flagName 的值设置为 something。其中 something 通常可以是任意值。

性能测试方法

原则1: 测试真实应用

应该在产品实际使用的环境中进行性能测试。性能测试大体上分为三种.

微基准测试

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

注意:

  1. 必须使用被测试的结果,否则会被 JVM 的智能编译器所优化掉。
  2. 不要包括无关的操作。

宏基准测试

介基准测试

原则2: 理解批处理流逝时间、吞吐量响应时间

测量应用性能的最简单的方法是,看它完成任务花了多少时间。由于 JIT 会优化代码,JVM 会预热,因此大多数时候,应该在运行代码足够长的时间,已经编译并优化之后再测量性能。

吞吐量:基于一段时间内所能完成的工作量。

响应时间:从客户段发送请求大收到响应之间的流逝时间。

负载生成器

介绍一个负载生成器 Faban http://faban.org/。其是一个开源的、基于 Java 的负载生成器。Faban 带有一个简单程序 (fhb),可以用来测试简单 URL 的性能:

$ fbh -W 1000 -r 300/300/60 -c 25 http://ip:oprt/xxx

这个了例子中用了 25 个客户端 -c 25,每个请求的周期时间为 1 秒 -W 1000,基准测试的热神器为 5 秒钟,以及 5 分钟测试周期和 1 分钟减速期 -r 300/300/60

原则3:用统计方法应对性能的变化

原则4: 尽早频繁测试

Java 性能调优的工具箱

待完善

JIT 编译器

待完善

垃圾手机入门

简单来说,垃圾收集由两部分构成:查找不再使用的对象;释放这些对象所管理的内存;

额外的,还有对堆的内存布局进行压缩整理。

所有应用线程都停止运行所产生的停顿并成为时空停顿(stop-the-world)。通常这些停顿对应用的性能影响最大。

5.1.1 分代垃圾收集器

貌似所有的垃圾收集器都遵循同一个方式,即根据情况将堆划分成不同的代(Generation)。

这些代被称为“老年代”(Old Generation 或 Tenured Generation)和“新生代” (Yong Generation)。

新声代又被进一步地划分为不同的区段,分别称为 Eden 空间和 Survivor 空间(不过 Eden 有时会被错误地用于指代整个新生代)。

采用分代机制的原因是很多的对象的生存时间非常短。

新生代是堆的一部分,对象首先在新生代中分配。新生代填满时,垃圾收集器会暂停所有的应用线程,回收新生代空间。不再使用的对象会被回收,仍然在使用的对象会被移动到其他地方。这种操作被称为 Minor GC。

采用这种设计有两个性能上的优势。其一,由于新生代仅是堆的一部分,与处理整个堆相比,处理新生代的速度更快。而这意味着应用线程停顿的间会更短。你可能也看到了这其中的权衡,这意味着应用程序线程会更频繁地发生停顿,因为JVM 不再等到整个堆都填满才进行垃圾收集;本章后续部分会针对其利弊进行深入的讨论。然而,就目前而言,更短的停顿显然能带来更多的优势,即使发生的频率更高。

第二个优势源于新生代中对象分配的方式。对象分配于Eden 空间(占据了新生代空间的绝大多数)。垃圾收集时,新生代空间被清空,Eden 空间中的对象要么被移走,要么被回收;所有的存活对象要么被移动到另一个Survivor 空间,要么被移动到老年代。由于所有的对象都被移走,相当于新生代空间在垃圾收集时自动地进行了一次压缩整理。

所有的垃圾收集算法在对新生代进行垃圾回收时都存在“时空停顿”现象。

对象不断地被移动到老年代,最终老年代也会被填满,JVM 需要找出老年代中不再使用的对象,并对它们进行回收。而这便是垃圾收集算法差异最大的地方。简单的垃圾收集算法直接停掉所有的应用线程,找出不再使用的对象,对其进行回收,接着对堆空间进行整理。这个过程被称为 Full GC,通常导致应用程序线程长时间的停顿。

另一方面,通过更复杂的计算,我们还有可能在应用线程运行的同时找出不再使用的对象;CMS 和G1 收集器就是通过这种方式进行垃圾收集的。由于它们不需要停止应用线程就能找出不再用的对象,CMS 和G1 收集器被称为Concurrent 垃圾收集器。同时,由于它们将停止应用程序的可能降到了最小,也被称为低停顿(Low-Pause)收集器(有时也称为无停顿收集器,虽然这个叫法相当不确切)。Concurrent 收集器也使用各种不同的方法对老年代空间进行压缩。

5.1.2 GC 算法

5.1.3 选择 GC 算法

5.2 GC 调优基础

5.2.1 调整堆的大小

5.2.2 代空间的调整

一旦堆的大小确定下来,你(或者JVM)就需要决定分配多少堆给新生代空间,多少给老年代空间。我们应该清楚地了解代的划分对性能的影响:如果新生代分配得比较大,垃圾收集发生的频率就比较低,从新生代晋升到老年代的对象也更少。任何事物都有两面性,采用这种分配方法,老年代就相对比较小,比较容易被填满,会更频繁地触发 Full GC。这里找到一个恰当的平衡点是解决问题的关键。

所有用于调整代空间的命令行标志调整的都是新生代空间;新生代空间剩下的所有空间都被老年代占用。多个标志都能用于新生代空间的调整,它们分别如下所列。

-XX:NewRatio=N   // 设置新生代与老年代的空间占用比率。
-XX:NewSize=N    // 设置新生代空间的初始大小。
-XX:MaxNewSize=N //设置新生代空间的最大大小。
-XmnN            // 将NewSize 和MaxNewSize 设定为同一个值的快捷方法。

5.2.3 永久代和元空间的调整

« EOF »

If you like TeXt, don’t forget to give me a star :star2:.