45 Java Performance Optimization Techniques (Part 1)

Preface: Since Japanese is not native, I think there are quite a few strange expressions and incorrect grammar, so I would appreciate it if you could point it out.

In a JAVA program, most of the performance issues are not in the JAVA language, but in the program itself. It is important to develop good coding habits that can significantly improve the performance of your program.

1. Make sure you use Singleton in the right place

While using singletons reduces load load, reduces load times, and improves load efficiency, not all locations are suitable for singletons.

Simply put, singletons can be applied to three main situations:

  1. Control resource usage and control concurrent resource access through thread synchronization.
  2. Control the instantiation to achieve the purpose of resource protection.
  3. You want to control data sharing and allow communication between multiple unrelated processes or threads without establishing a direct association.

2. Don't use static variables freely

If an object is defined as a static variable, GC typically does not reclaim the memory occupied by that object.

public class A {
  private static B b = new B();
}

At this time, the life cycle of static variable b is synchronized with class A. If class A is not unloaded, the b object will remain in memory until the program exits.

3. Don't create too many Java objects

Not only does the system take a long time to create objects, but it also takes a long time to garbage collect and process these objects, so try to avoid creating new objects in frequently called loops and methods. .. It is best to replace the object with a basic data type or array.

4. Try using the final modifier

Classes with the final modifier cannot be derived. There are many examples of Java core APIs with finals such as java.lang.String. For example, specifying final in the String class prevents the user from overriding the length () method. In addition, if the class is final, all methods in that class will be final. The Java compiler looks for opportunities to inline all final methods (this is relevant to the implementation of a particular compiler). This will improve performance by an average of 50%.

5. Use local variables as much as possible

When the method is called, the parameters passed and the temporary variables created by the call are faster to be stored on the stack. On the other hand, other variables such as static variables and instance variables are created on the heap and are slower than the stack.

6. Try to handle both boxing and primitive types

Boxing types and primitive types can be converted to each other during use. However, the memory areas generated by both are completely different. Primitive type generation and processing is done on the stack, and since box types are objects, they instantiate in the heap. The use of primitive types is recommended except in situations where you need to work with box types, such as collections.

7. Minimize synchronization

As we all know, synchronization is a big system overhead and can even cause deadlocks, so try to avoid unnecessary synchronization control. When the synchronize method is called, the current object is locked directly and no other thread can call other methods of the current object until the method finishes. Therefore, synchronization methods are minimized and method synchronization should be used instead of code block synchronization.

8. Don't use the finalize method

The GC workload is so heavy that the application pauses, especially when Young memory is recycled, so if you use the finalize method to clean up resources at this time, the GC load will be heavy and the program operation will be slow. Become.

9. Try to use basic data types instead of objects

String str = "hello";

The above code will create a "hello" string, and the JVM's character cache pool will also cache this string.

String str = new String("hello");

At this time, in addition to creating the string, the String object referenced by str also contains a char [] array. This array contains h, e, l, l, o.

10. For multithreading, use HashMap and ArrayList whenever possible when you don't need to consider thread safety

HashTable, Vector, etc. use a synchronization mechanism, which reduces performance.

11. Create a HashMap that is as rational as possible

If you want to create a large HashMap, specify the capacity and load factor in the constructor below as much as possible.

public HashMap(int initialCapacity, float loadFactor);

Avoid extending the HashMap. Expansion is very costly.

By default, the initialCapacity is 16 and the loadFactor is 0.75, but it's important to accurately estimate how much space you need and the optimal size you need. The same is true for Hashtable and Vectors.

12. Reduce double calculation of variables

for(int i=0;i<list.size();i++)

in the case of

for(int i=0,len=list.size();i<len;i++)

Must be changed to.

Do not use complex expressions in loops. In a loop, the loop condition is calculated iteratively. By not changing the value of the loop condition without using complex expressions, the program runs faster.

13. Try to avoid unnecessary instantiation

For example:

A a = new A();

if(i==1){

  list.add(a);

}

in the case of,

if(i==1){

  A a = new A();

  list.add(a);

}

Should be changed to.

14. Finally free resources with blocks

Resources used by the program should be released to avoid resource leaks. This is best done in a finally block. Regardless of the result of running the program, finally blocks are always executed to ensure that resources are properly closed.

15. Let's use shift operation instead of'a / b'

The "/" is a very expensive operation and it is faster and more efficient to use the shift operation. For example

int num = a / 4;

int num = a / 8;

in the case of,

int num = a >> 2;

int num = a >> 3;

Should be changed to. However, the shift operation is intuitive and difficult to understand, so it's better to add comments when using shift.

16. Let's use shift operation instead of'a * b'

Similarly, for'*' operations, it is faster and more efficient to use shift operations.

For example

int num = a * 4;

int num = a * 8;

in the case of,

int num = a << 2;

int num = a << 3;

Should be changed to.

17. The capacity of StringBuffer should be decided in advance as much as possible.

The StringBuffer constructor creates an array of characters of default size (usually 16). If this size is exceeded during use, memory will be reallocated, a larger array will be created, the original array will be copied, and the old array will be discarded.

In most cases, you can specify the size when you create a StringBuffer. This allows you to avoid auto-expansion that occurs when there is not enough capacity and improve performance.

18. Release references to useless objects as soon as possible

In most cases, the program does not need to explicitly set the reference variable to null, because in most cases the object referenced by the method's local reference variable will be trashed at the end of the method.

For example

Public void test(){

Object obj = new Object();

……

obj=null;

}

In the above code, you don't need to explicitly execute ´obj = null´.

The reference to obj is released when the execution of method test () is complete.

But if the program is modified as follows:

public void test(){

Object obj = new Object();

// ……

Obj=null;

//Time-consuming, memory-intensive operations, or time-consuming, memory-intensive methods are called

// ……

}

At this time, by explicitly assigning null to obj, the reference to Object can be released at an early stage.

19. Avoid using 2D arrays as much as possible

Two-dimensional data occupies much more memory space than one-dimensional arrays. It is about 10 times.

20. Don't use split

Because split supports regular expressions, it is relatively inefficient and consumes a lot of resources. Consider using Apache's StringUtils.split (string, char), which can be cached frequently.

21. ArrayList and LinkedList

One is a linear table, one is a linked list, and in conclusion, ArrayList is better than LinkedList if you call get frequently. In the case of LinkedList, it is necessary to scan one by one. On the other hand, if you call add or remove frequently, LinkedList is better than ArrayList. ArrayList needs to move data.

This is a theoretical analysis. Understand the data structures of both, and take appropriate measures according to the situation.

22. Use System.arraycopy () instead of looping and copying arrays

System.arraycopy () is much faster than looping and copying an array.

23. Cache your favorite objects

To cache frequently used objects, you can cache them using arrays or HashMap containers. However, this method uses too much cache on the system and results in poor performance. We recommend using a third-party open source tool such as EhCache. Oscache is cached and they basically implement a cache algorithm like FIFO / FLU.

Recommended Posts

45 Java Performance Optimization Techniques (Part 1)
java practice part 1
Java Performance Chapter 1 Introduction
Java app performance tuning
Studying Java ~ Part 8 ~ Cast
Java Performance Chapter 3 Java Performance Toolbox
Java and Iterator Part 1 External Iterator
Java Performance Chapter 2 Performance Testing Approach
Apache Hadoop and Java 9 (Part 1)
Exception handling techniques in Java
Java Servlet / JSP Request Scope Part 1
Java to learn with ramen [Part 1]
Java Servlet / JSP Request Scope Part 2
Basic usage of java Optional Part 1
Server processing with Java (Introduction part.1)
Creating lexical analysis in Java 8 (Part 2)
GAE / Java8 trial (Part 6: "Deployment failure")
Java Performance Chapter 5 Garbage Collection Basics
Creating lexical analysis in Java 8 (Part 1)