This is the 26th day of my participation in the August Text Challenge.More challenges in August

preface

This article continues where we left off: Understanding the JVM – Compiler optimization (Part 1)

An overview of the

  1. Another element that complements backend optimization is to advance the compiler’s processing

  2. Introduces several key optimization measures for the JVM

    1. Method inlining (important)

    2. Escape analysis (advanced)

    3. Common subexpression Elimination (classic)

    4. Array boundary checking elimination

The back-end optimization

Ahead of time compiler

The history of precompilers has been around for a long time, but it wasn’t until the rise of Andirod that Java became aware of the precompilers that we looked at the pros and cons of precompilers before going into the concerns about precompilers

advantages

  • Solve the real-time compiler to occupy computing resources in the program.

  • Just-in-time compiler cache acceleration

  • Pre-compiled code quality.

    What do you mean by interprocess analysis?

    Current Java is not optimized for interprocedural analysis and can be optimized throughout the program due to static compilation.

The practice of the Java

For the above advantages, JDK9 implements a Jactc advance compiler. Having said the advantages of the just-in-time compiler, here are the advantages of the just-in-time compiler:

  1. Performance analysis guides optimization: For some dynamic code and abstract methods, dynamic analysis is available

  2. Radical optimizations: You can do deep optimizations that are not guaranteed to be correct, and you can fall back into the protector.

  3. Link-time optimization: Java naturally supports just-in-time compilation to produce native code.

You only need a basic understanding of precompilation. Let’s look at some more low-level optimizations for the JVM.

The underlying optimization

The following is a list of low-level JVM optimizations, such as method inlining, redundant duplication elimination, replication propagation, useless code elimination, and more. Here are a few picks from the book:

  • Method inlining (important)

  • Escape analysis (advanced)

  • Common subexpression Elimination (classic)

  • Array boundary checking elimination

Methods the inline

Meaning: To move an inline method inside an inline block. In simple terms, multiple nested method calls are merged into a single method to reduce frame pile-up.

How to do that?

The prerequisites for implementation: First, it must be a non-virtual method, that is, a static method that can be called without a virtual method.

C and C++ use explicit virtual and non-virtual methods to plan boundaries.

Specific implementation of Java: the introduction of type inheritance relationship analysis and implementation, determine in the current loaded class, whether there is more than one implementation of an interface, whether there is a subclass of a class, whether a subclass overrides a virtual method of the parent class and other information “.

The above can be briefly summarized as the following points:

  1. Determine the implementer of the interface and whether it can be implemented

  2. Whether there is an inheritance relationship

  3. Whether there is an override method

Methods the escape

The basic principle of escape analysis is to analyze the dynamic scope of objects. When an object is defined in a method, it may be referenced by external methods, for example, as a call parameter to other methods.

An object can be referred to externally in a method definition, which leads to an important optimization tool: stack allocation, which simply reduces heap space allocation and improves memory reclamation.

Java only supports method escape, not thread escape.

The book describes the current situation of escape analysis as follows:

  1. There is a lot of room for improvement

  2. Jdk6 is only initially supported

  3. Complex algorithms are involved

Another optimization is scalar substitution:

What are scalars: Variables are scalars if they cannot be represented in fewer units (int, byte, Boolean, etc.).

What is an aggregate quantity: the quantity that can be further decomposed is called an aggregate quantity.

Scalar replacement: Disassembles a Java object and uses it for member variable recovery and access based on program access.

Combining escape analysis with scalar substitution, ** escape analysis does not create objects that cannot be accessed externally and can be represented by scalar substitution. ** also re-emphasizes that only in-method processing is supported, not method escape.

Then there is the optimization of synchronous elimination:

Synchronization elimination: Thread synchronization itself is a relatively time-consuming process. If escape analysis can determine that a variable cannot escape from the thread and be accessed by other threads, then there must be no contention between reads and writes of the variable, and synchronization of the variable can be safely eliminated.

Finally, if a variable does not escape, move the unsynchronization measure.

Common subexpression

What is a common subexpression? If an expression E has been evaluated before and the values of all variables in E have not changed since the previous evaluation, the occurrence of E is called a common subexpression. There is no need to take the time to re-evaluate the expression, just replace E with the result of the previously evaluated expression.

Case study:

int d = (c * b) * 12 + a + (a + b * c);
Copy the code

If the expression is evaluated once, it is replaced with the following:

int d = E * 12 + a + (a + E);
Copy the code

Array boundary checking eliminated

Java arrays are different from C and C ++ arrays, which are not operated in the way of bare Pointers. In order to ensure safe access to arrays, the bottom layer of THE JVM needs to check the boundaries of arrays every time it operates, that is, a judgment with head and tail: [start, end].

In response to this problem, Java considers optimization in the following way:

  1. If the array access scope can be defined, the consumption of array access can be offset in theory

  2. Finish ahead of compile time

  3. Implicit exception handling: such as null Pointers and exceptions with a divisor of 0.

Final treatment:

Register with a segment fault signal to ensure that no null operation is performed when most accesses are not null. Once an exception is raised, it goes to an exception handler and throws an exception.

But there are problems with this approach: ** Frequent transitions between user and kernel modes. ** But hotspot makes a dynamic decision to use boundary checking elimination or to run in the original policy mode based on how it actually works.

conclusion

This is a very simple section that covers JVM tuning, including subsequent low-level tuning. There is a lot more to low-level tuning, but this article has only documented four important tuning methods mentioned in the book.

Write in the last

Now that you’ve covered the basics of the JVM, the next section concludes.