(Code level) Java Performance Optimization

Source: Internet
Author: User

Java performance optimization (I)

 

Huang Weifeng

After the emergence of Java in the middle of 1990s, it attracted some criticism while winning praise. What I have won is mainly the cross-platform operability of Java, the so-called "write once, run anywhere ". however, the performance and running efficiency of Java are still quite different from those of C, attracting a lot of criticism.
For server-side applications, because interface design and frequent Program Restart are not involved, Java's performance problems seem insignificant, and some java technologies, such as JSP, se rvlet, EJB has been widely used in server-side programming. However, Java performance problems still exist on the server side. I will discuss Java performance and execution efficiency in four aspects and some methods to improve J Ava performance.
1. Basic Performance knowledge
1. Performance Definition
Before we discuss how to improve Java's performance, we need to understand the true meaning of "performance. We generally define the following five aspects as the criteria for judging performance.
1) performance of operations-which algorithm has the best execution performance?
2) memory allocation ---- how much memory the program needs to allocate, with the highest efficiency and performance during runtime.
3) Start time ---- how long it takes to start the program.
4) program scalability-the performance of a program when the user load is too heavy.
5) Performance Understanding ------ how can Users recognize the performance of programs.
Different applications have different performance requirements. For example, most applications take a long time to start, reducing the startup time requirement. server applications usually allocate a large amount of memory space, therefore, the memory requirements are also reduced. However, these two aspects of performance can not be ignored. Secondly, the performance of algorithms is very important for applications that apply business logic to transactional operations. In general, the requirements for applications will determine the priority of each performance.
2. How to improve Java Performance
To improve Java performance, we generally consider the following four main aspects:
(1) programming methods and models
A good design can improve the program performance, which is not only applicable to Java, but also any programming language. It makes full use of various resources, such as memory, CPU, high-speed cache, Object Buffer Pool, and multithreading, to design a high-performance and scalable system.
Of course, it is difficult to change the original design to improve the program performance. However, the importance of the program performance is often higher than the changes brought about by the design. Therefore, there should be a good design model and method before Programming starts.
(2) Java deployment environment.
Java environment refers to the technology used to interpret and execute Java bytecode. There are generally five types. Interpreter technology, just in time compilier technology, adaptive Optimization Technology, dynamic optimization, dynamic Optimization (ahead of time technology) and machine code compilation (translator technology ).
These technologies generally optimize Java performance by optimizing the thread model and adjusting the heap and stack size. To improve Java performance, first find the bottleneck that affects Java performance (B ottlenecks). After confirming the rationality of the design, adjust the Java deployment environment, modify some parameters to Improve the Performance of Java applications. For details, see section 2.
(3) Implementation of Java applications
When discussing the performance of an application, most programmers will consider the program code, which is of course correct. More importantly, find the bottleneck code that affects the program performance. To find these bottleneck codes, we generally use auxiliary tools such as J probe, optimizit, vtune, and some analysis tools such as towerj performance. These auxiliary tools track the time consumed by each function or method in the application to improve the program performance.
(4) hardware and Operating System
In order to improve the performance of Java applications, the CPU and more memory are adopted, and this is the only way to improve program performance, but this is not the case. Practical experience and facts prove that the most effective method is to take appropriate measures, such as the design model, deployment environment, and operating system adjustment, only when the application performance bottleneck is met.
3. Common performance bottlenecks in the program.
All applications have performance bottlenecks. To improve the performance of applications, We must minimize the bottlenecks. The following are common performance bottlenecks in Java programs.

After learning about these bottlenecks, we can reduce these bottlenecks to Improve the Performance of Java applications.
4. Steps to improve Java program performance
To improve the performance of Java programs, follow these six steps.
A) define specific performance requirements
Before implementing a project, you must specify the project's specific requirements for program performance. For example, the application must support 5000 concurrent users and the response time should be within 5 seconds. However, you must also understand that the performance requirements should not conflict with other requirements on the program.
B) understand the performance of the current program
You should understand the gap between the performance of your application and the performance required by the project. The common metric is the number of processes and response time per unit time, and sometimes the CPU and memory utilization are compared.
C) Find the performance bottleneck of the program
To discover performance bottlenecks in a program, some analysis tools, such as towerj Application Performance Analyzer or vtune, are usually used to view and analyze the time consumed by each element in the program stack, in this way, you can find and correct the bottleneck code that causes performance degradation to improve the program performance. These tools can also detect potential problems such as excessive Exception Handling and garbage collection.
D) Take appropriate measures to improve performance
After finding the bottleneck code that causes program performance degradation, we can use the four aspects described earlier to improve performance, namely the design mode and Java code implementation, deploy the Java environment and operating system to improve the application performance. The specific content is described in detail in the following content.
E) modify only one aspect to improve performance.
Only change one aspect that may cause performance degradation at a time, and then observe whether the performance of the program has improved, instead of changing multiple aspects at a time, in this way, you will not know which change improves the performance of the program, and which one does not, that is, you cannot know where the program bottleneck is.
F) return to Step C and continue to do similar work until the required performance is reached.

II. Environment and compilation technology deployed in Java
When developing a Java application, compile the Java source program into a platform-independent bytecode. These bytecode can be executed by various JVM-based technologies. These technologies are mainly divided into two categories. That is, the explanation-based and the locally compiled code in advance. It is as follows:

It can be divided into the following five categories:
A) Explain instruction technology
Its structure and execution process are as follows:

The Java compiler first compiles the Java source file into bytecode. These bytecode are machine instructions for Java Virtual Machine (JVM. Then, the Java interpreter continuously fetches bytecode for interpretation and execution.
This feature enables cross-platform Java language and compact the generated bytecode. Java has some advantages, such as security and dynamic. However, the disadvantage is that the byte code generated by the province has not been optimized, Which is slower than the locally compiled code.
B) timely compilation technology (Just In Time)
The timely compilation technique is proposed to solve the problem of low efficiency and slow speed of instruction interpretation. Its structure is shown below.

The main change is that before Java program execution, the JIT compiler compiles Java bytecode into machine code. Therefore, the machine code is executed directly when the program is running, instead of explaining the bytecode. The Code is also partially optimized.
This greatly improves the performance of Java programs. At the same time, because the compilation results are not saved between programs, the storage space is also saved to load the program. The disadvantage is that the j It compiler wants to optimize all the code, therefore, a lot of time is wasted.
Both IBM and SUN provide relevant JIT products.
C) Adaptive Optimization Technology)
Compared with JIT technology, adaptive Optimization Technology does not optimize all bytecode. It will track the process of running the program and discover the code to be optimized and dynamically optimize the code. Use a 0/20 strategy for optimized code. Theoretically, the longer the program runs, the more optimized the code. The structure is as follows:

The advantage is that adaptive Optimization Technology makes full use of information during program execution and releases performance bottlenecks to improve program performance. Its disadvantage is that it may be improperly selected during optimization, program performance is reduced.
Its main products are IBM and Sun's hotspot.
D) Dynamic Optimization and machine code compilation in advance (dynamic optimization, ahead of time)
The dynamic optimization technology fully utilizes the Java source code compilation, bytecode compilation, dynamic compilation, and static compilation technologies. The source code or bytecode of Java is input, while the output is a combination of highly optimized executable code and a dynamic library (DLL files in windows and shared libraries in UNIX. a. so file ). Its structure is as follows:

Its advantage is that it can greatly improve the performance of the program. Its disadvantage is that it damages Java's portability and brings some hidden risks to Java's security.

Java performance optimization (II)

 

Huang Weifeng
 
3. Some methods to optimize Java programming and coding and improve Java program performance.
You can use some auxiliary tools described earlier to locate the bottleneck in the program, and then optimize the code of the bottleneck. There are generally two solutions: optimize the code or change the design method. We usually select the latter, because not calling the following code is better than calling some optimized code to improve the performance of the program. A well-designed program can streamline code and improve performance.
The following provides some methods and techniques that are often used in the design and coding of Java programs to improve the performance of Java programs.
1. Object generation and size adjustment.
A common problem in Java programming is that the functions provided by the Java language are not used properly, so a large number of objects (or instances) are often generated ). Because the system not only takes time to generate objects, it may take time to recycle and process these objects. Therefore, generating too many objects will greatly affect the program performance.
Example 1: String, stringbuffer, +, and append
The Java language provides operations for string-type variables. However, improper use may affect the program performance. The following statement:
String name = new string ("huangweifeng ");
System. Out. println (name + "is my name ");
It seems to have been quite streamlined, but not actually. To generate binary code, perform the following steps and operations.
(1) generate a new string (str_1 );
(2) copy the string.
(3) load the String constant "huangweifeng" (str_2 );
(4) constructor );
(5) Save the string to the array (starting from position 0)
(6) obtain the static out variable from the java. Io. printstream class.
(7) generate a new string buffer variable new stringbuffer (str_buf_1 );
(8) copy the buffer variable of this string
(9) Call the constructor );
(10) Save the string to buffer it into the Array (starting from position 1)
(11) using str_1 as the parameter, call the append method in the string buffer class.
(12) load the String constant "is my name" (str_3 );
(13) using str_3 as the parameter, call the append method in the string buffer class.
(14) execute the tostring command for str_buf_1.
(15) Call the println method in the out variable to output the result.
The two simple lines of code generate five object variables str_1, str_2, str_3, str_4, and str_buf_1. The instances of these generated classes are generally stored in the heap. The heap needs to initialize the super classes and class instances of all classes, and also call the framework of every super class of the class. These operations consume a lot of 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 (name. append ("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 buffer variable of this string
(3) load the String constant "huangweifeng" (str_1 );
(4) Call the constructor );
(5) Save the string to buffer it into the Array (starting from position 1)
(6) obtain the static out variable from the java. Io. printstream class.
(7) Load str_buf_1;
(8) load the String constant "is my name" (str_2 );
(9) using str_2 as the parameter, call the append method in the string buffer instance.
(10) execute the tostring command for str_buf_1. (Str_3)
(11) Call the println method in the out variable to 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 think that generating less than one object will not greatly improve the program performance. However, the execution speed of code segment 2 below will be twice that of code segment 1. Because code segment 1 generates eight objects, while 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, making full use of the library functions provided by Java to optimize the program is very important to improve the performance of the Java program. The main points of attention are as follows;
(1) use static class variables as much as possible)
If the variable in the class does not change with his instance, it can be defined as a static variable so that all his instances share the variable.
Example:
Public class foo
{
Someobject so = new someobject ();
}
It can be defined:
Public class foo
{
Static someobject so = new someobject ();
}
(2) do not change the generated object too much.
For some classes (such as the string class), we would rather regenerate a new object instance than 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 to be recycled by the system. If you want to connect strings, the performance will be worse. Because the system will not generate more temporary variables for this. As shown in Example 1 above.
(3) When generating an object, allocate reasonable space and size to it.
Many classes in Java have their default space allocation size. For the stringbuffer class, the default allocated space is 16 characters. If the size of the space used by stringbu ffer in the program is not 16 characters, initialization must be performed correctly.
(4) avoid generating unused objects or variables with short lifecycles.
In this case, an object buffer pool is defined. The overhead of managing an Object Buffer Pool is much lower than that of frequently generated and recycled objects.
(5) Only initialize within the scope of the object.
Java allows objects to be defined and initialized anywhere in the code. In this way, initialization can only be performed within the scope of the object. This saves system overhead.
Example:
Someobject so = new someobject ();
If (x = 1) then
{
Foo = So. getxx ();
}
It can be changed:
If (x = 1) then
{
Someobject so = new someobject ();
Foo = So. getxx ();
}
2. Exceptions)
In Java, try/catch is provided to help you catch and handle exceptions. However, improper use may also affect the performance of Java programs. Therefore, pay attention to the following two points.
(1) Avoid using try/catch for application logic
If you can use logic statements such as if and while, try not to use try/catch statements.
(2) Reuse exception
When exceptions must be handled, try to reuse existing exceptions as much as possible. It takes most of the time to generate an exception object during exception handling.
3. threading)
Threads are generally used in a high-performance application. Because threads can make full use of system resources. When other threads wait for hard disk or network read/write, the program can continue to process and run. However, improper use of threads may also affect program performance.
Example 2: Correctly Use the Vector class
Vector is mainly used to save various types of objects (including objects of the same type and different types ). However, in some cases, application performance may be affected. This is mainly determined by the two features of the V Ector class. First, vector provides thread security protection. Even if many methods in the vector class are synchronized. However, if you have confirmed that your application is a single thread, the synchronization of these methods is completely unnecessary. Second, it usually takes a lot of time to perform type matching when V Ector searches for various stored objects. However, when these objects are of the same type, these matches are completely unnecessary. Therefore, it is necessary to design a single-threaded class that saves classes or sets of specific types of objects to replace the V Ector class. The program 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 <count; I ++)
{
// Check for a match
If (data [I]. Equals (STR ))
{
System. arraycopy (data, I + 1, Data, I, Count-1); // copy data
// Allow previusly 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 *****************/
Therefore, the Code:
Vector strings = new vector ();
Strings. Add ("one ");
Strings. Add ("two ");
String second = (string) strings. elementat (1 );
You can replace it with the following code:
Stringvector strings = new stringvector ();
Strings. Add ("one ");
Strings. Add ("two ");
String second = strings. getstringat (1 );
In this way, the Java program performance can be improved by optimizing the thread. The program used for testing is 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. addelement ("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 test results are as follows (assuming the standard time is 1, the smaller the performance is, the better ):

Pay attention to the following aspects for thread operations.
(1) prevent excessive Synchronization
As shown above, unnecessary synchronization often causes program performance degradation. Therefore, if the program is a single thread, do not use synchronization.
(2) synchronous method instead of synchronizing the entire code segment
It is better to synchronize a method or function than to synchronize the entire code segment.
(3) Use multiple "locks" mechanism for each object to increase concurrency.
Generally, each object has only one "Lock", which indicates that if two threads execute two different Synchronization Methods of an object, a "deadlock" will occur ". Even if the two methods do not share any resources. To avoid this problem, you can implement a "Multi-lock" mechanism for 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 Output include many aspects, but the most involved is read and write operations on hard disks, networks, or databases. For read/write operations, there are cache and no cache; for database operations, there can be multiple types of J-DBC drives to choose from. But in any case, it will affect the performance of the program. Therefore, pay attention to the following points:
(1) Use the input/output buffer
Use as much cache as possible. If you need to refresh the cache frequently (flush), we recommend that you do not use the cache.
(2) output stream and Unicode string
When output stream and Unicode strings are used at that time, the overhead of the write class is relatively large. It must convert Unicode to byte. Therefore, if possible, it can be converted before using the write class or replaced by the writer class using the O utputstream class.
(3) Use transient when serialization is required
When serializing a class or object, the atomic type (atomic) or the element that can be reconstructed must be recognized as the transient type. This eliminates the need to serialize each time. If these serialized objects are to be transmitted over the network, this small change will greatly improve the performance.
(4) using high-speed cache)
Objects or data that are frequently used but not changed can be stored in the cache. In this way, the access speed can be improved. This is especially important for the result set returned from the database.
(5) Use a fast JDBC driver)
Java provides four methods for accessing the database. Two of them are JDBC drives. One is a local drive outsourced using Java; the other is a full Java drive. Which one should be used depends on the environment and application of Java deployment.
5. Some other experiences and skills
(1) Use local variables
(2) Avoid calling functions or methods (get or set) in the same class to set or call variables.
(3) avoid generating the same variable or calling the same function in a loop (the same is true for parameter variables)
(4) use static, final, private, and other keywords as much as possible
(5) When copying a large amount of data, use the system. arraycopy () command.

Related Article

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.