In-depth understanding of Java Virtual Machine (14th) correct use of JVM inline

Source: Internet
Author: User

In-depth understanding of Java Virtual Machine (14th) correct use of JVM inline

In IntelliJ IDEA, Ctrl + Alt + M is used to split the method. Select a piece of code and click this combination, which is very simple. Eclipse also uses a similar shortcut key, using Alt + Shift + M. I hate long methods. I think it is too long to mention the following method:

public void processOnEndOfDay(Contract c) {if (DateUtils.addDays(c.getCreated(), 7).before(new Date())) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if (sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);}}

First, it has a condition to judge the readability is very poor. No matter how it is implemented, what it does is the most critical. Let's split it first:

public void processOnEndOfDay(Contract c) {if (isOutDate(c)) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if (sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);}}private boolean isOutDate(Contract c) {return DateUtils.addDays(c.getCreated(), 7).before(new Date());}

Obviously, this method should not be put here:

public void processOnEndOfDay(Contract c) {if (c.isOutDate()) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if (sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);}}

Have you noticed anything different? My IDE changed the isOutdated Method to the Contract instance method. But I am still upset. This method is too complicated. A branch is processing business-related logic priorityHandling, as well as sending system notifications and logging. The other branch sends system notifications based on the judgment conditions and records logs. We first split the processing of expired contracts into an independent method.

public void processOnEndOfDay(Contract c) {if (c.isOutDate()) {handleOutdated(c);} else {if (sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);}}private void handleOutdated(Contract c) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);}

Some people may think this is good enough, but I think the two branches are not symmetrical. The handleOutdated method has a higher level, while the else branch is more detailed. The software should be clear and easy to read, so do not mix code at different levels. In this way, I will be more satisfied:

public void processOnEndOfDay(Contract c) {if (c.isOutDate()) {handleOutdated(c);} else {stillPending(c);}}private void stillPending(Contract c) {if (sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);}private void handleOutdated(Contract c) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);}

This example seems a bit installation, but what I want to prove is another thing. Although it is not common now, some developers do not dare to split the method, so they are worried that this will affect the running efficiency. They don't know that JVM is actually a great piece of software (it is actually a few steps away from the Java language), and it has many very surprising runtime optimizations. First, the short method is more conducive to JVM inference. The process is more obvious, the scope is shorter, and the side effects are more obvious. If it is a long method, the JVM may just kneel down. The second reason is more important:

Method inline

If the JVM detects that some small methods are frequently executed, it replaces the method call with the method body. For example, the following:

private int add4(int x1, int x2, int x3, int x4) {return add2(x1, x2) + add2(x3, x4);}private int add2(int x1, int x2) {return x1 + x2;}

It is certain that after running for a period of time, JVM will remove the add2 method and translate your code:

private int add4(int x1, int x2, int x3, int x4) {return x1 + x2 + x3 + x4;}

Note that this is about JVM, not the compiler. Javac is conservative when generating bytecode, and these tasks are all done by JVM. It turns out that such a design decision is wise:

The JVM is more clear about the target environment, CPU, memory, and architecture. It can be more actively optimized. JVM can discover the features of your code runtime, such as which method is frequently executed and which virtual method has only one implementation. The. class compiled by the old compiler can run faster on the new JVM version. Update the JVM and re-compile the source code. You certainly prefer the latter.

We will test these assumptions. I wrote a small program with the title of the worst implementation of the rule of separation. The add128 method requires 128 parameters and calls the add64 method twice-the first and second half each time. Add64 is similar, but it calls add32 twice. You guessed it right. In the end, the add2 method will end all of this. It is hard-working. I have omitted some numbers, so it's easy to see your eyes:

public class ConcreteAdder {   public int add128(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128) {    return add64(x1, x2, x3, x4, ... more ..., x63, x64) +        add64(x65, x66, x67, x68, ... more ..., x127, x128);  }   private int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64) {    return add32(x1, x2, x3, x4, ... more ..., x31, x32) +        add32(x33, x34, x35, x36, ... more ..., x63, x64);  }   private int add32(int x1, int x2, int x3, int x4, ... more ..., int x31, int x32) {    return add16(x1, x2, x3, x4, ... more ..., x15, x16) +        add16(x17, x18, x19, x20, ... more ..., x31, x32);  }   private int add16(int x1, int x2, int x3, int x4, ... more ..., int x15, int x16) {    return add8(x1, x2, x3, x4, x5, x6, x7, x8) + add8(x9, x10, x11, x12, x13, x14, x15, x16);  }   private int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8) {    return add4(x1, x2, x3, x4) + add4(x5, x6, x7, x8);  }   private int add4(int x1, int x2, int x3, int x4) {    return add2(x1, x2) + add2(x3, x4);  }   private int add2(int x1, int x2) {    return x1 + x2;  }} 

It is not hard to find that a total of 127 method calls are generated after the add128 method is called. Too many. For reference, the following is a simple and direct implementation version:

public class InlineAdder {     public int add128n(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128) {        return x1 + x2 + x3 + x4 + ... more ... + x127 + x128;    } }

Finally, an abstract class and an inherited implementation version are used. The call overhead of the 127 virtual methods is very large. These methods need to be dynamically distributed, so higher requirements are required, so they cannot be inline.

public abstract class Adder {   public abstract int add128(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128);   public abstract int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64);   public abstract int add32(int x1, int x2, int x3, int x4, ... more ..., int x31, int x32);   public abstract int add16(int x1, int x2, int x3, int x4, ... more ..., int x15, int x16);   public abstract int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8);   public abstract int add4(int x1, int x2, int x3, int x4);   public abstract int add2(int x1, int x2);} 

There is also an implementation:

public class VirtualAdder extends Adder {   @Override  public int add128(int x1, int x2, int x3, int x4, ... more ..., int x128) {    return add64(x1, x2, x3, x4, ... more ..., x63, x64) +        add64(x65, x66, x67, x68, ... more ..., x127, x128);  }   @Override  public int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64) {    return add32(x1, x2, x3, x4, ... more ..., x31, x32) +        add32(x33, x34, x35, x36, ... more ..., x63, x64);  }   @Override  public int add32(int x1, int x2, int x3, int x4, ... more ..., int x32) {    return add16(x1, x2, x3, x4, ... more ..., x15, x16) +        add16(x17, x18, x19, x20, ... more ..., x31, x32);  }   @Override  public int add16(int x1, int x2, int x3, int x4, ... more ..., int x16) {    return add8(x1, x2, x3, x4, x5, x6, x7, x8) + add8(x9, x10, x11, x12, x13, x14, x15, x16);  }   @Override  public int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8) {    return add4(x1, x2, x3, x4) + add4(x5, x6, x7, x8);  }   @Override  public int add4(int x1, int x2, int x3, int x4) {    return add2(x1, x2) + add2(x3, x4);  }   @Override  public int add2(int x1, int x2) {    return x1 + x2;  }} 

Inspired by some enthusiastic readers of my other article on @ Cacheable load, I wrote a simple benchmark to compare the loads of these two overly-split ConcreteAdder and VirtualAdder. The results were surprising, and some people were confused. I did a test on two machines (red and blue). The same program is different because the second machine has more CPU cores and is 64-bit:


Specific Environment Information:
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + pgltzybzcm9 "http://www.2cto.com/uploadfile/Collfiles/20141020/20141020084841335.png" alt = "n blocks L % Su fabricated l tease '?- =? L? # J. zookeeper? R has been running wM ?? Coupon z + & z ;v) %x) %f ...? Http://www.bkjia.com/kf/qianduan/css/ "target =" _ blank "class =" keylink "> html
Http://it.deepinmind.com/java/2014/03/01/jvm's internal link. html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.