(Code level) Java performance optimization

xiaoxiao2021-03-06  61

Java performance optimization (on)

Huang Weifeng

After the mid-1990s, Java has also attracted some criticisms while winning. Winner is mainly the Java's cross-platform operability, that is, the so-called "Write Once, Run Anywhere". However, due to the performance of Java, there is still a lot of gaps compared to the Running efficiency, there is a lot of gaps. criticism.

For the server-side applications, the performance problem of Java seems to be significant, so that some Java technology, such as JSP, SE RVLET, EJB, etc. are obtained in server-side programming. Very large application, but in fact, Java performance issues still exists on the server. Below I will discuss the performance and implementation efficiency of Java and improve the Java performance of Java.

One. Basic knowledge about performance

1. Definition of performance

We need to understand the true meaning of "Performance" before we discuss how to improve Java performance. We generally define the following five aspects as the criteria for judging performance.

1) Performance of the operation - - Which algorithm is performed in performance performance?

2) The allocation of memory ---- The program needs to assign how much memory, the efficiency and performance of the runtime.

3) Start time ---- How much time it takes to start.

4) The scalability of the program ----- the performance of the program in the case of user load.

5) Performance's understanding ------ How can users recognize the performance of the program.

For different applications, the requirements for performance are also different. For example, most applications take longer time at startup, thereby decreasing the starting time; the application of the server is usually allocated with large memory space, so the requirements for memory are also reduced. However, this is not that the performance of the two aspects can be ignored. Second, the performance of the algorithm is very important for applications that use business logic to transactional operations. In general, the requirements for the application will determine the priority to each performance.

2. How can I improve the performance of Java?

Improve Java performance, generally considering the following four main aspects:

(1) Method and mode for programming

A good design can improve the performance of the program, which is not only suitable for Java, but also any programming language. Because it makes full use of various resources, such as memory, CPU, cache, object buffer pools and multithreades, thereby designing high performance and scalable systems.

Of course, in order to improve the performance of the program, it is more difficult to change the original design, but the importance of program performance is often higher than the design of the design. Therefore, there should be a good design model and method before the programming begins.

(2) Environment of Java deployment.

The environment of Java deployment refers to techniques for explaining and executing Java bytecles, usually as follows. That interpretation INSTRUCTIONS (Interpreter Technology), Technical time compiler (Just In Time Compilier Technology), adaptive optimization technique (Adaptive Optimization Technology), dynamic optimization, machine code is compiled ahead technique (Dynamic Optimization, Ahead Of Time Technology) And compile as machine code (Translator Technology).

These technologies are generally optimized by optimizing thread models, adjusting the size of the stack and stack to optimize Java performance. When considering improving the performance of Java, you must first find bottlenecks that affect Java performance, after confirming the rationality of the design, the Java deployment environment should be adjusted to improve the performance of the Java application by changing some parameters. See Section 2 of the specific content. (3) Realization of Java applications

When discussing the performance of the application, most of the programmers considerate the code of the program, which is of course right, when more important is to find bottleneck code affecting the program performance. In order to find these bottleneck code, we generally use some auxiliary tools, such as J Probe, OptimizIzit, VTune, and some analysis tools such as Towerj Performance. These assisted tools can track the time consumed by each function or method in the application, thereby improving the performance of the program.

(4) Hardware and operating systems

In order to improve the performance of the Java application, use Fast CPUs and more memory, and believe that this is the only way to improve program performance, but this is not the case. Practical experience and facts have proven that only the application performance bottlenecks, there is appropriate way, such as design patterns, deployment, and operating system adjustments, is the most effective.

3. The usual performance bottleneck in the program.

All applications have performance bottlenecks. In order to improve the performance of the application, it is necessary to reduce the bottleneck of the program as much as possible. The following is a performance bottleneck that often exists in the Java program.

After you understand these bottlenecks, you can reduce these bottlenecks, thereby improving the performance of Java applications.

4. Steps to improve the performance of the Java program

In order to improve the performance of the Java program, the following six steps are needed.

a) Clear specific requirements for performance

Before implementing a project, you must clarify the specific requirements for program performance, such as this application to support 5000 concurrent users, and the response time is within 5 seconds. But it also understands that the requirements for performance should not conflict with other requirements of the program.

b) Understand the performance of the current program

You should understand the performance of your application with the gap between the performance requirements of the project. The usual indicator is the number of processing and response time in unit time, and sometimes the utilization of CPU and memory is compared.

c) Find the performance bottleneck of the program

In order to find out the performance bottleneck in the program, some analytics tools are usually used, such as: TowerJ Application Performance Analyzer or VTune to see and analyze the time consumption time of each element in the program stack, thus correctly find and correct the bottleneck code that causes performance reduced. Improve the performance of the program. These tools can also find potential issues such as excessive abnormalities, garbage collection.

d) take appropriate measures to improve performance

After finding the bottleneck code that caused the program performance, we can use the four aspects of the improvement in the previously introduced, namely design patterns, Java code implementations, deployment Java environment and operating systems to improve the performance of the application. The details will be described in detail in the following.

e) Improve performance only on certain aspects of modification

Once only change, only one aspect of the performance can be reduced, then the performance of the program is improved, and it should not change multiple aspects at a time, because you will not know which aspect change improves the performance of the program, which aspect No, you can't know where the program bottleneck is.

f) Return to step c, continue to work similar to the performance, which has been achieved.

two. Java deployment environment and compilation technology

When developing a Java application, first compile the Java source program into a byte code that is not related to the platform. These bytes can be performed by various JVM-based technologies. These technologies are mainly divided into two large categories. That is, a technique based on the interpretation and technique based on the pre-compiled as local code. The schematic is as follows: specifically divided into the following five categories:

a) explain the instruction technology

The structural diagrams and execution processes are as follows:

Java's compiler first compiles the Java source file as a bytecode. These bytes are the Java Virtual Machine (JVM) is the machine's instruction code. Then, Java's interpreter continuous loops takes out the bytecode and executes.

The advantage of this is that the cross-platform of the Java language can be implemented, and the generated bytecode is also compacted. Some of Java, such as security, dynamics have to be kept; but the disadvantage is that the province's generated bytecode is not optimized, and the speed is slower than all compiled local code.

b) Compilation Technology in time (Just In Time)

Timely compilation technology is to solve the instruction interpretation technology is relatively low, and the speed is relatively slow, and the structural diagram is shown below.

Its main change is to compile JAVA's bytecode as machine code before the Java program is executed. Thereby directly executing the machine code directly at runtime without using the bytecode. At the same time, the code also has been partially optimized.

The advantage of this is that it greatly improves the performance of the Java program. At the same time, since the results of the compilation are not stored in the program running, the time saving the loader is saved; the disadvantage is that the J IT compiler is optimized for all the code, so a lot of time is also wasted.

IBM and Sun provide relevant JIT products.

c) Adaptive Optimization Technology (ADAPTIVE OPTIZATION TECHNOLOGY)

Adaptive optimization techniques are not optimized for all bytecods compared to JIT technology. It tracks the procedure of the program run, thus discovering the code that needs to be optimized, and dynamically optimized the code. For optimized code, take 8 0/20 strategies. In theory, the longer the program is running, the more optimized the code. The structural diagram is as follows:

The advantage is that adaptive optimization techniques take advantage of the information execution time, the performance bottleneck of the issuer, thereby increasing the performance of the program; its disadvantage is that improper selection when optimizing, and reduces the performance of the program.

Its main products are IBM, and SUN's Hotspot.

d) Dynamic optimization, compile as machine code in advance (Dynamic Optimization, Ahead of Time)

Dynamic optimization technology fully utilizes Java source code compilation, bytecode compile, dynamic compilation, and static compilation techniques. The original code or bytecode of Java is input, and the output is a mixture of highly optimized executable code and a dynamic library (a DLL file in Window, and the shared library in Unix is ​​a shared library .a .so file). The structure is as follows:

Its advantage is to greatly improve the performance of the program; the disadvantage is to destroy Java's portability and bring a certain hidden danger for Java's security.

Optimization of Java performance (below)

Huang Weifeng

three. Optimize the Java program design and encoding, improve some of the methods of Java program performance.

Find the bottleneck in the program by using some of the previously described auxiliary tools, and then optimize the code of the bottleneck portion. There are generally two options: optimizing code or changing design methods. We generally choose the latter, because you don't call the following code to improve program performance than call some optimized code. And a well-designed program can streamline the code to improve performance.

Some methods and techniques that are often used in the design and encoding of the Java program, and some methods and techniques that are often used in the design and encoding of the Java program.

1. Adjustment of the generation and size of the object.

A common problem in the Java program is that there is no function provided by the Java language itself, which often generates a large number of objects (or instances). Since the system not only takes time to generate an object, it may still take time to take the time to garbage recycling and processing. Therefore, excessive objects will have a big impact on the performance of the program. Example 1: About String, StringBuffer, and Append

The Java language provides operations for String type variables. However, if not used, it will affect the performance of the program. As of the following statement:

String name = new string ("HuangWeifeng");

System.out.println (Name "Is My Name");

It seems that it is very streamlined, it is not the case. In order to generate binary code, the following steps and operations are processed.

(1) Generate a new string new string (STR_1);

(2) Copy the string.

(3) Load the string "HuangWeifeng" (STR_2);

(4) Arrival (constructor) of the string;

(5) Save the string to the array (starting from position 0)

(6) Get static OUT variables from java.io.printStream class

(7) Generate a new string buffer variable new stringbuffer (str_buf_1);

(8) Copy the string buffer variable

(9) Call structor;

(10) Save the string buffer to an array (starting from position 1)

(11) The APPEND method in the string buffer class is called in STR_1.

(12) Loading a string constant "is my name" (STR_3);

(13) The APPEND method in the string buffer class is called in STR_3.

(14) Execute the toString command for STR_BUF_1.

(15) Call the PrintLn method in the OUT variable, output the result.

It can be seen that the two lines of simple code generates STR_1, STR_2, STR_3, STR_4, and STR_BUF_1 five object variables. Examples of these generated classes are generally stored in the heap. Piles are initialized for all classes, classes of all classes, while also calling an extremely super-class architecture. These operations are very consumed system resources. Therefore, it is necessary to limit the generation of objects.

After modification, the above code can be replaced with the following code.

StringBuffer name = new stringbuffer ("HuangWeifeng");

System.out.println ("IS my name."). TOSTRING ());

The system will perform the following operations.

(1) Generate a new string buffer variable new stringbuffer (str_buf_1);

(2) Copy the string buffer variable

(3) Load string often "huangweifeng" (STR_1);

(4) Call the string buffer architecture (constructor);

(5) Save the string buffer to an array (starting from position 1)

(6) A static OUT variable (7) is loaded from the Java.io.PrintStream class to load STR_BUF_1;

(8) Load string constant "is my name" (STR_2);

(9) The Append method in the string buffer instance is called in STR_2.

(10) Execute the toString command for STR_BUF_1. (STR_3)

(11) Call the PrintLn method in the OUT variable and output the result.

It can be seen that the improved code only generates four object variables: STR_1, STR_2, STR_3 and STR_BUF_1. You may feel that less generation of an object will not increase the performance of the program. However, the execution speed of the code segment 2 below will be twice the code segment 1. Since the code segment 1 generates eight objects, the code segment 2 generates only four objects.

Code segment 1:

String name = new stringbuffer ("huangweifeng");

Name = "is my";

Name = "Name";

Code segment 2:

StringBuffer name = new stringbuffer ("HuangWeifeng");

Name.Append ("is my");

Name.append ("name."). TOSTRING ();

Therefore, fully utilizing the library function provided by Java to optimize the program, which is very important to improve the performance of the Java program. The attention points mainly have the following aspects;

(1) Use Static Class Variables as possible

If the variables in the class do not change with his instance, you can define a static variable so that all the instances share this variable.

example:

Public Class Foo

{

SomeObject so = new homeObject ();

}

It can be defined as:

Public Class Foo

{

Static SomeObject SO = New SomeObject ();

}

(2) Do not change too much of the generated object.

For some classes (such as: String class), prefer to regenerate a new object instance without modifying the generated object instance.

example:

String name = "huang";

Name = "wei";

Name = "feng";

The above code generates three String type object instances. The first two immediately need system for garbage collection. If you want to connect to a string, performance will be worse. Because the system will not generate more temporary variables for this. As shown in the first example.

(3) When the object is generated, it is assigned to it to reasonably space and the size.

Many classes in Java have its default spatial allocation size. For StringBuffer classes, the default assignment space size is 16 characters. If the spatial size of the StringBU Ffer in the program is not 16 characters, the correct initialization must be performed.

(4) Avoid generating objects or variables shorter or shorter life cycle.

For this case, an object buffer pool is defined. It is to manage a smaller cost of managing a target buffer pool than frequent generation and recycling objects.

(5) Initialization only within the target scope.

Java allows you to define and initialize the object anywhere in your code. In this way, it can be initialized only within the range of the object. Thereby saving the overhead of the system.

example:

SomeObject so = new homeObject ();

IF (x == 1) THEN

{

FOO = sol .getxx ();

}

Can be modified to:

IF (x == 1) THEN {

SomeObject so = new homeObject ();

FOO = sol .getxx ();

}

2. Excetions

Try / catch in the Java language is provided to facilitate user capture exception and perform an exception. But if you use improper use, it will also affect the performance of the Java program. Therefore, pay attention to the following two points.

(1) Avoid using TRY / CATCH logic to applications

If you can use if, while, etc., you can handle it, then don't use TRY / CATCH statement as much as possible.

(2) Reusing exception

When the processing must be processed, it is necessary to reuse the existing exception objects as much as possible. Those in the abnormal process, generating an abnormal object to consume most of the time.

3. Threading

A thread is generally used in a high-performance application. Because threads make full use of the resources of the system. In other threads, the program can continue to process and run because of the other threads waiting for the hard disk or network read and write. However, it is used to use improper use and will affect the performance of the program.

Example 2: Use the Vector Class Correctly

Vector is primarily used to save various types of objects (including the same type and different types of objects). However, in some cases, use the performance of the program to bring performance. This is mainly determined by the two features of the V ECTOR class. First, Vector provides thread safety protection features. Even many methods in the Vector class synchronize. But if you have confirmed that your application is a single thread, the synchronization of these methods is completely unnecessary. Second, when V Ector finds various objects stored, it often spends a lot of time to match the type. These matches are completely unnecessary when these objects are in the same type. Therefore, it is necessary to design a single-threaded, saving a class or collection of a particular type of object to replace the V Ector class. The program used to replace is as follows (StringVector.java):

Public Class StringVector

{

PRIVATE STRING [] DATA;

PRIVATE INT COUNT;

Public stringvector () {this (10); // default size is 10}

Public StringVector (int initialsize)

{

Data = new string [initialsize];

}

Public Void Add (String STR)

{

// ignore null strings

IF (str == null) {return;}

EnsureCapacity (count 1);

Data [count ] = STR;

}

Private Void EnSurecapacity (int MINCAPACITY)

{

INT Oldcapacity = data.length;

IF (MINCAPACITY> Oldcapacity)

{

String olddata [] = data;

INT newcapacity = Oldcapacity * 2;

Data = new string [newcapacity];

System.ArrayCopy (OldData, 0, Data, 0, Count);

}

}

Public Void Remove (String Str)

{

IF (str == null) {return // ignore null str}

For (int i = 0; i

{

// Check for a match

IF (Data [i] .Equals (str))

{

System.Arraycopy (Data, i 1, Data, I, Count-1); // Copy Data // Allow Previously Valid Array Element Be gc'd

Data [- count] = NULL;

Return;

}

}

}

Public final string getStringat (int index) {

IF (INDEX <0) {Return Null;}

Else if (INDEX> count)

{

Return null; // index is> # strings

}

Else {Return Data [INDEX]; // Index is good}

}

/ * * * * * * * * * * * * * * Stringvector.java * * * * * * * * * * * * * * * * /

So, code:

Vector strings = new vector ();

Strings.Add ("one");

Strings.Add ("Two");

String second = (string) strings.ementat (1);

Can be replaced with the following code:

StringVector strings = new stringvector ();

Strings.Add ("one");

Strings.Add ("Two");

String second = strings.getstringat (1);

This can improve the performance of the Java program by optimizing the thread. The procedures for test are as follows: TestCollection.java:

Import java.util.vector;

Public Class TestCollection

{

Public static void main (string args [])

{

TestCollection Collect = New TestCollection ();

IF (args.length == 0)

{

System.out.println (

"USAGE: JAVA TESTCOLLECTION [Vector | StringVector]");

System.exit (1);

}

IF (args [0] .equals ("vector"))

{

Vector store = new vector ();

Long Start = system.currenttimemillis ();

For (int i = 0; i <1000000; i )

{

Store.AddeElement ("string");

}

Long finish = system.currenttimemillis ();

System.out.println (FINISH-START);

Start = system.currenttimemillis ();

For (int i = 0; i <1000000; i )

{

String result = (string) Store.Elementat (i);

}

FINISH = system.currenttimemillis ();

System.out.println (FINISH-START);

}

Else IF (Args [0]. Equals ("stringvector")))

{

StringVector store = new stringvector ();

Long Start = system.currenttimemillis (); for (int i = 0; i <1000000; i ) {store.add ("string");}

Long finish = system.currenttimemillis ();

System.out.println (FINISH-START);

Start = system.currenttimemillis ();

For (int i = 0; i <1000000; i ) {

String result = store.getstringat (i);

}

FINISH = system.currenttimemillis ();

System.out.println (FINISH-START);

}

}

}

/ * * * * * * * * * * * * * * Testcollection.java * * * * * * * * * * * * * * * * /

The results of the test are as follows (assuming the standard time is 1, the smaller performance, the better):

For the operation of thread, pay attention to the following aspects.

(1) Prevent excessive synchronization

As shown above, unnecessary synchronization often causes a decline in program performance. Therefore, if the program is a single thread, you must not use synchronization.

(2) Synchronous method instead of synchronizing the entire code segment

Synchronizing a method or function is better than synchronizing the entire code segment.

(3) Increase the mechanism for each object using multiple "lock".

Generally, each object has only one "lock", which indicates that "dead lock" occurs if two threads perform two different synchronization methods of an object. Even if these two methods do not share any resources. To avoid this problem, you can implement "multi-lock" mechanisms to an object. As follows:

Class foo

{

Private static int var1;

Private static object lock1 = new Object ();

Private static int var2;

Private static object lock2 = new object ();

Public static void increment1 ()

{

Synchronized (LOCK1)

{

Var1 ;

}

}

Public static void increment2 ()

{

SYNCHRONIZED (LOCK2)

{

VAR2 ;

}

}

}

4. Input and output (I / O)

Input and outputs include many aspects, but involving the most is the read and write operations for hard drives, networks, or databases. For read and write operations, it is divided into cache and no cache; for the operation of the database, there can be several types of J DBC drivers to choose. But no matter what, it will affect the performance of the program. Therefore, pay attention to the following:

(1) Use the input and output buffer

Use more caches as much as possible. However, if you want to refresh the cache, it is recommended not to use a cache.

(2) Output stream and Unicode string

When using Output Stream and Unicode strings, the WRITE class has a big overhead. Because it is to implement Unicode to byte (Byte) conversion. Therefore, if possible, the conversion is implemented before using the WRITE class, or use the O UtputStream class instead of the Writer class.

(3) Use Transient when serialization

When serialization of a class or object, it is to recognize the TRANSIENT type for those atomic or reconstructed grades. This will not be serialized each time. If these serialized objects are transmitted over the network, this small change has great improvement in performance. (4) Using Cache (cache)

For objects or data that are often used and unclear, it can be stored in the cache. This will increase the speed of access. This is especially important for the result set returned from the database.

(5) Using a fast JDBC drive (Driver)

Java provides four ways to access the database. There are two kinds of JDBC drivers. One is a local drive out of Java; the other is a complete Java drive. Specifically, which one is to be determined according to the J ava deployment environment and the application itself.

5. Some other experiences and techniques

(1) Use local variables

(2) Avoid setting or calling the variables in the same class during the same class (GET or SET).

(3) Avoid generating the same variable in the loop or call the same function (the parameter variable is also the same)

(4) Use Static, Final, Private and other keywords as possible

(5) When copying a large amount of data, use the system.araycopy () command.

转载请注明原文地址:https://www.9cbs.com/read-118865.html

New Post(0)