Ibm just-In-Time Compiler (jit) for Java: Best Practices and Coding Guidelines for improving Performance



Yüklə 153,14 Kb.
Pdf görüntüsü
səhifə3/7
tarix07.11.2018
ölçüsü153,14 Kb.
#78937
1   2   3   4   5   6   7

 

 

 



Inlining 

One of the strengths of Java and other object-orientated programming languages is their ability to 

modularize and reuse code in the form of packages, classes and methods.  

Strategy: Aggressively inline method calls 

Currently, the unit of compilation that the JIT compiler considers is a single method. To make 

optimizations more effective, the JIT compiler aggregates small methods into larger ones through 

effective inlining. Inlining is a technique where a method call is replaced with the target method’s 

bytecodes. This technique increases the scope of compilation beyond a single method. Inlining is also 

a powerful way to propagate information into target methods, thereby reducing uncertainty in the 

application code and making optimizations more effective. 

Virtual and interface methods 

Virtual and interface methods in Java provide a useful abstraction for developers. However, this 

abstraction comes with an associated performance cost, because polymorphic calls might have multiple 

target implementations during the execution of the application. Furthermore, the uncertainty of the target 

method at these call sites can limit the optimizations that the JIT compiler performs, such as inlining. 



Strategy: Devirtualize as many call sites as possible 

However, the TRJIT compiler tries to overcome such constraints by using devirtualization techniques, 

whereby a single-target implementation is chosen and the JIT transforms the virtual call to a direct 

call. The JIT can use profiling or class hierarchy analysis [5] to detect that the receiver of a virtual call 

is predominantly of a certain type. The transformation needs to be done with a virtual-guard test in 

place to ensure that the correct target method is invoked in all cases for functional correctness. 

Figure 1 shows an example of this transformation. 

o = receiver object ;  

x = receiver class (o) ;  

 

if ( x == expected-class )  { // virtual guard 



 

 

x.foo(a, b, c) ; 



   // direct call can be inlined 

 

} else { 



 

 

o.foo(a, b, c) ; 



   // guard failed, virtual call 

 



Figure 1: Example of Devirtualization

 

Certain guards can be removed if they are proven to be unnecessary, based on the current class 

hierarchy during the execution of the application. If a new class is loaded during the execution of the 

application that changes the hierarchy of the class involved in a guard, then the TRJIT reinserts the 

guard to maintain correct behavior. 

IBM Just-In-Time Compiler (JIT) for Java 

Best practices and coding guidelines for improving performance 



 

 

 



Heap allocations 

Java allocates objects on the heap. Therefore, references to objects might need to go through multiple 

levels of the memory hierarchy, which includes the processor cache and main memory. Data locality is 

important because hardware cache misses can lead to poor application performance. An application that 

allocates many objects with a short lifespan can have reduced performance because of potential heap 

fragmentation and poor locality, resulting in more hardware-cache misses. One of the ways in which the 

TRJIT compiler helps data locality (and in turn, performance) is by converting heap allocations into stack 

allocations when possible [3]. 



Strategy: Optimize for object locality 

Using the stack for short-lived allocations leads to better locality because the stack is usually 

available in the cache. This reduces memory latencies that result from cache misses. As an added 

benefit, using the stack for short-lived allocations reduces the load on the garbage collector because 

these allocations are no longer present in the heap. 

The TRJIT compiler attempts to find allocations that never escape the method in which they are 

allocated. See the example shown in Figure 2, where the allocation of the Integer object, intObj, is 

local to method m1 and does not escape the method. The TRJIT compiler can convert this allocation 

into a stack-allocation.  

public class myClass { 

public static void m1() { 

Integer intObj = new Integer(100); //intObj does not escape m1 

System.out.println(“Value is: “+ intObj.intValue()); 



Figure 2. intObj does not escape m1 and can be stack-allocated 

 

However, in Figure 3, the allocation is stored into a field of another object and is, therefore, not local 



to the method m1. 

public class myClass { 

public static void m1(myClass myObj) { 

Integer intObj = new Integer(100); 

myObj._myField = intObj; 

 

// intObj escapes m1 



System.out.println(“Value is: “+ intObj.intValue()); 

public Integer _myField; 





Figure 3. intObj is stored into the field of another object, thus escaping, and cannot be stack-allocated 

IBM Just-In-Time Compiler (JIT) for Java 

Best practices and coding guidelines for improving performance 


 

 

 



Java coding guidelines 

This section presents a set of Java coding guidelines that are based on analyzing the performance of 

various Java applications. The focus is on four areas with the most impact on application performance. 

Object allocations 

Object allocations are not cheap in Java because, after memory is allocated for an object, the object 

needs to be initialized before it is accessible to the program. This involves zero-initializing the object fields 

as well as invoking the constructor to perform initializations as specified by the user.  

Guideline: Avoid creating objects inside loops 

Objects that are allocated inside loops have a short lifespan and might not survive subsequent 

iterations of the loop. For example, you can avoid creating objects inside loops to improve 

performance of String concatenation operations. Although it is not obvious, the javac compiler 

implicitly allocates a java/lang/StringBuilder object when you use the plus (+) concatenation operator. 

It is more efficient to explicitly use java/lang/StringBuilder to build a string than to use the + 

concatenation operator.  

Figure 4, Figure 5 and Figure 6 show an example of this.  

In Java, strings are immutable. Therefore, in Figure 4Error! Reference source not found., the 

character x is not appended to the string that str points to. The concatenation + operator implicitly 

creates a StringBuilder object and copies the string (which str points to) into this new object. It then 

appends the character x to the contents of the new object.  

public class myClass { 

 

public static int N = 10000; 



public static void main(String [] argv) { 

String str = “”; 

for (int i = 0; i < N; i++) 

   str = str + “x”; 



Figure 4. Example of avoiding unnecessary allocations: New objects implicitly created inside loop on every iteration 



Figure 5 shows the code that javac generates.  

public class myClass { 

 

public static int N = 10000; 



public static void main(String [] argv) { 

String str = “”; 

for (int i = 0; i < N; i++) 

   StringBuilder sb = new StringBuilder(); 

   sb.append(str); 

   sb.append(“x”); 

   str = sb.toString();    



Figure 5. Example of avoiding unnecessary allocations: Code generated by javac for loop in Figure 3a 

IBM Just-In-Time Compiler (JIT) for Java 

Best practices and coding guidelines for improving performance 


Yüklə 153,14 Kb.

Dostları ilə paylaş:
1   2   3   4   5   6   7




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə