From:http://www.jdon.com/performance/java-performance-optimizations.html
当Java执行runtime环境时,每遇到一个新的类,JIT编译器在此时就会针对这个类别进行编译(compile)被优化成相当精简的原生型指令码(native code),会做一下工作:
首先,JIT会展开我们代码中的循环语句,所以,我们编码时尽量注意不要在关键热点部分编写让JIT难于展开的循环语句。
JIT比较难以展开的循环语句如下:
int i = 0; for (;;) { if (array.length == i) { break; } doSomething(array[i++]); }
这种for循环虽然编写方便,但是JIT不喜欢,下面循环则易于JIT展开:
int i = 0; for (int i = 0; i < array.length; i++) { doSomething(array[i]); }
其次,JIT会内联一些热点小方法代码,这些小方法缺省差不多是325字节。比如下面是普通代码:
public void methodA() { ... // Do some work A methodB(); } private void methodB() { ... // Do some more work B }
JIT会将methodB内联合并到methodA中
//采取methodB内联到到methodA public void methodA() { ... // Do some work A ... // Do some more work B }
可以通过下面的Java运行配置记录检测内联:
java
-XX:+PrintCompilation
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining
.... > inline.log
PrintCompilation:当JIT编译发生输出打印
UnlockDiagnosticVMOptions:这是标识 -XX:+PrintInlining需要的
-XX:+PrintInlining :当方法被内联后打印出来
内联日志inline.log效果如下:
@ 42 io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe::read (191 bytes) inline (hot) (这表示方法hot被内联了)
@ 42 io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe::read (327 bytes) hot method too big (但是方法hot用于内联太大了)
@ 4 io.netty.channel.socket.nio.NioSocketChannel::config (5 bytes) inline (hot)
@ 1 io.netty.channel.socket.nio.NioSocketChannel::config (5 bytes) inline (hot)
@ 12 io.netty.channel.AbstractChannel::pipeline (5 bytes) inline (hot)
我们编码时对于热点方法不要编写对内联太大的方法,如下面read方法:
private final class NioMessageUnsafe extends AbstractNioUnsafe { public void read() { final SelectionKey key = selectionKey(); if (!config().isAutoRead()) { int interestOps = key.interestOps(); if ((interestOps & readInterestOp) != 0) { // only remove readInterestOp if needed key.interestOps(interestOps & ~readInterestOp); } } ... // rest of the method } ... }
分解出read() 方法一部分代码到新的方法中:
private final class NioMessageUnsafe extends AbstractNioUnsafe { public void read() { if (!config().isAutoRead()) { removeReadOp(); } private void removeReadOp() { SelectionKey key = selectionKey(); int interestOps = key.interestOps(); if ((interestOps & readInterestOp) != 0) { // only remove readInterestOp if needed key.interestOps(interestOps & ~readInterestOp); } } ... // rest of the method } ...
注意到read方法从原来多行已经变成了简单几行,这时我们再看看JIT的内联日志:
@ 42 io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe::read (288 bytes) inline (hot)
只有一行输出,说明read方法已经小到适合内联了。