Highlights of Java Performance Optimization Techniques

Source: Internet
Author: User

Resources available for the Program (memory, CPU time, network bandwidth, etc.) are limited. The purpose of optimization is to allow the program to complete the scheduled tasks with as few resources as possible. Optimization usually involves two aspects: reducing the size of the code and improving the code running efficiency. This article focuses on how to improve code efficiency.

  I. General

The general topic is suitable for most Java applications.

1.1 create a class instance without the New Keyword

When you create an instance with the New Keyword, all constructors in the constructor chain are automatically called. But if an object implements the cloneable interface, we can call its clone () method. The clone () method does not call any class constructor.

When using design pattern, it is very easy to use the clone () method to create a new object instance if you create an object in factory mode. For example, the following is a typical Implementation of the factory mode:

  

Public static credit getnewcredit ()

{

Return new credit ();

}

The improved code uses the clone () method as follows:

  

Private Static credit basecredit = new credit ();

Public static credit getnewcredit ()

{

Return (credit) basecredit. Clone ();

}

The above idea is also useful for Array Processing.

1.2 use non-blocking I/O

Earlier JDK versions do not support non-blocking I/O APIs. To avoid I/O congestion, some applications use the method of creating a large number of threads (in good cases, a buffer pool is used ). This technology can be seen in many applications that must support concurrent I/O streams, such as web servers, quote and auction applications. However, creating a Java thread requires considerable overhead.

JDK 1.4 introduces a non-blocking I/O Library (Java. NiO ). If an application requires JDK of an earlier version, there is a software package that supports non-blocking I/O.

1.3 usage exceptions with caution

Exceptions are detrimental to performance. To throw an exception, you must first create a new object. The constructor of the throwable interface calls the local (native) method named fillinstacktrace (), the fillinstacktrace () method checks the stack, and collects Call trace information. As long as an exception is thrown, the VM must adjust the call stack because a new object is created during processing.

Exceptions can only be used for error handling and should not be used to control program processes.

1.4 do not reinitialize the variable

By default, Java initializes the variable to a definite value when calling the class constructor: all objects are set to null, and integer variables (byte, short, Int, long) set it to 0, float and double variables to 0.0, and logical value to false. This is especially important when a class is derived from another class, because when an object is created using the new keyword, all constructors in the constructor chain are automatically called.

1.5 specify the final modifier of the class as much as possible

Classes with final modifiers cannot be derived. There are many examples of final applications in the Java core API, such as Java. Lang. String. Specifying final for the string class prevents people from overwriting the length () method.

In addition, if you specify a class as final, all the methods of this class are final. The Java compiler will look for opportunities to inline (Inline) All final methods (this is related to the specific compiler implementation ). This can increase the performance by an average of 50%.

1.6 use local variables whenever possible

The parameters passed during method calling and the temporary variables created in the call are saved in the stack, which is faster. Other variables, such as static variables and instance variables, are created in heap, which is slow. In addition, local variables may be further optimized depending on the specific compiler/JVM. See use stack variables whenever possible.

1.7 multiplication and division

Consider the following code:

For (val = 0; Val <100000; Val + = 5)

{

Alterx = Val * 8;

Myresult = Val * 2;

}

Replacing multiplication with shift operations can greatly improve performance. The modified code is as follows:

For (val = 0; Val <100000; Val + = 5)

{

Alterx = Val <3;

Myresult = Val <1;

}

The modified code does not multiply by 8. Instead, it uses the equivalent three-bit left shift operation, and one-bit left shift operation is equivalent to multiplying 2. Correspondingly, the one-bit operation on the right is equivalent to dividing by 2. It is worth mentioning that, although the shift operation is fast, it may make the code more difficult to understand, so it is best to add some comments.

  Ii. J2EE

The performance improvement techniques described earlier are suitable for most Java applications. The questions to be discussed later are suitable for JSP, EJB, or JDBC applications.

2.1 use a buffer flag

Some application servers have added the JSP-oriented buffer tag function. For example, the WebLogic Server of BEA supports this function from version 6.0, and the open symphony project also supports this function. The JSP buffer tag can buffer both page fragments and the whole page. When the JSP page is executed, if the target segment is already in the buffer, the code that generates the segment will no longer need to be executed. Page-level buffer captures requests to a specified URL and caches the entire result page. This feature is extremely useful for shopping baskets, directories, and portals. For such applications, page-level buffering can save the results of page execution for subsequent requests.

For pages with complex code logic, the performance improvement by using the buffer tag is obvious; otherwise, the performance may be slightly inferior.

2.2 always access the Entity Bean through the session bean

Direct access to the Entity Bean is not conducive to performance. When the client program remotely accesses the object bean, each get method is a remote call. The Session Bean accessing the object bean is local. It organizes all the data into a structure and returns its value.

The access to the Entity Bean encapsulated by the session bean can improve the transaction management, because the Session Bean will be submitted only when it reaches the transaction boundary. Each direct call to the get method generates a transaction, and the container will execute a "load-read" operation after each Entity Bean transaction.

In some cases, using the Entity Bean will lead to poor program performance. If the only purpose of the entity bean is to extract and update data, you can use JDBC to access the database within the session bean to achieve better performance.

2.3 select an appropriate reference mechanism

In a typical JSP application system, the page header and footer are often extracted, and the page header and footer are introduced as needed. Currently, there are two main methods to introduce external resources in JSP pages: include commands and include actions.

Include command: for example. This command introduces specified resources during compilation. Before compilation, the page with the include command and the specified resource are merged into a file. The referenced external resources are determined at compilation, which is more efficient than the resources determined at runtime.

Include action: for example . This action introduces the result generated after the specified page is executed. Because it is completed at runtime, the control of output results is more flexible. However, the include action is cost-effective only when the referenced content changes frequently or the referenced page cannot be determined before the request to the home page appears.

2.4 set the read-only attribute in the deployment descriptor

The deployment descriptor of the Entity Bean allows you to set all get methods to "read-only ". When a transaction unit only includes read operations, setting the read-only attribute improves performance because the container does not have to perform storage operations.

2.5 Buffer access to EJB home

The EJB home interface is obtained through the JNDI name search. This operation requires considerable overhead. It is best to put the JNDI search in the init () method of servlet. If multiple applications frequently encounter EJB access, it is best to create an ejbhomecache class. The ejbhomecache class is generally implemented as Singleton.

2.6 implement Local interface for EJB

The Local interface is newly added to the EJB 2.0 specification, which allows the bean to avoid the overhead of remote calls. Consider the following code.

Paybeanhome home = (paybeanhome) javax. RMI. portableremoteobject. Narrow (CTX. Lookup ("paybeanhome"), paybeanhome. Class );

Paybean bean = (paybean) javax. RMI. portableremoteobject. Narrow (home. Create (), paybean. Class );

The first statement indicates that we are looking for the home interface of bean. This query is performed through JNDI, which is an Rmi call. Then, we locate the remote object and return the proxy reference, which is also an Rmi call. The second statement demonstrates how to create an instance. It involves the stub program that creates an IIOP request and transmits the request over the network. It is also an Rmi call.

To implement the local interface, we must make the following changes:

The method cannot throw a java. RMI. RemoteException, including exceptions derived from RemoteException, such as transactionrequiredexception, transactionrolledbackexception, and nosuchobjectexception. EJB provides equivalent local exceptions, such as transactionrequiredlocalexception, transactionrolledbacklocalexception, and nosuchobjectlocalexception.

All data and return values are passed through reference instead of values.

The Local interface must be used on the machine where the EJB is deployed. In short, the customer program and the components that provide services must run on the same JVM.

If bean implements a local interface, its reference cannot be serialized.

2.7 generate a primary key

There are many ways to generate a primary key in EJB. The following describes several common methods and their features.

Use the database's built-in identity mechanism (SQL Server's identity or Oracle's sequence ). The disadvantage of this method is that EJB has poor portability.

The Entity Bean automatically calculates the primary key value (for example, incremental operations ). Its disadvantage is that transactions must be serializable and slow.

Use NTP and other clock services. This requires that you have local code for a specific platform to fix the bean to a specific OS. In addition, it also leads to the possibility that two primary keys are generated within the same millisecond on a multi-CPU server.

Use Microsoft's idea to create a guid in bean. However, if you do not turn to JNI, Java cannot determine the MAC address of the NIC; if you use JNI, the program depends on a specific OS.

There are several other methods, but these methods also have their own limitations. There seems to be only one ideal answer: combining RMI and JNDI. Bind the remote RMI object to the JNDI tree through RMI registration. The customer program searches through JNDI. The following is an example:

Public class keygenerator extends unicastremoteobject implements remote

{

Private Static long keyValue = system. currenttimemillis ();

Public static synchronized long getkey () throws RemoteException {return keyValue ++ ;}

2.8 clear unnecessary sessions in time

To clear sessions that are no longer active, many application servers have the default session timeout time, usually 30 minutes. When the application server needs to save more sessions, if the memory capacity is insufficient, the operating system will transfer some memory data to the disk, the application server may also dump some inactive sessions to the disk based on the most recently used algorithm, or even throw a "out-of-memory" exception. In large-scale systems, serialized sessions are expensive. When the session is no longer needed, you should promptly call httpsession. invalidate () to clear the session. The httpsession. invalidate () method can be called on the exit page of the application.

2.9 close useless sessions on the JSP page

For pages that do not need to track session Status, disabling automatically created sessions can save some resources. Use the following page command:

<% @ Page session = "false" %>

2.10 Servlet and memory usage

Many developers store a large amount of information in user sessions at will. In some cases, objects stored in sessions are not recycled in a timely manner by the garbage collection mechanism. In terms of performance, the typical symptom is that the user feels the system slows down cyclically, but cannot attribute the cause to any specific component. If you monitor the heap space of the JVM, the memory usage may fluctuate abnormally.

There are two main ways to solve such memory problems. The first method is to implement the httpsessionbindinglistener interface in all beans with the function scope of the session. In this way, the bean resources can be explicitly released as long as the valueunbound () method is implemented.

Another method is to invalidate the session as soon as possible. Most application servers have the option of setting the session expiration time. In addition, you can call the setmaxinactiveinterval () method of the session programmatically. This method is used to set the maximum interval of customer requests allowed by the servlet container before the session is voided, in seconds.

2.11 HTTP keep-alive

The keep-alive function keeps the client-to-server connection valid. When a subsequent request is sent to the server, the keep-alive function avoids or reestablishes a connection. Most Web servers on the market, including iPlanet, IIS, and Apache, Support HTTP keep-alive. This feature is usually useful for websites that provide static content. However, for websites with heavy load, there is another problem here: although it is advantageous to keep the opened connection for the customer, it also affects the performance, because during the pause process, resources that can be released are still in use. When the Web server and Application Server run on the same machine, the impact of the keep-alive function on resource utilization is particularly prominent.

2.12 JDBC and Unicode

You must have understood some measures to improve the performance when using JDBC, for example, using the connection pool, correctly selecting stored procedures and directly executing SQL statements, deleting redundant columns from the result set, and pre-compiling SQL statements.

In addition to these obvious options, another good choice for improving performance may be to save all the character data as Unicode (code page 13488 ). Java processes all data in unicode format. Therefore, the database driver no longer needs to execute the conversion process. But remember: if this method is used, the database will become larger, because each UNICODE character requires 2 bytes of storage space. In addition, if other non-Unicode programs access the database, performance problems still occur, because the database driver must still execute the conversion process.

2.13 JDBC and I/O

If an application needs to access a large dataset, consider using block extraction. By default, JDBC extracts 32 rows of data each time. For example, if we want to traverse a 5000-row record set, JDBC must call the database 157 times to extract all the data. If the block size is changed to 512, the number of database calls will be reduced to 10.

In some cases, this technology is ineffective. For example, if you use a scrollable record set or specify for update in the query, the block operation method is no longer valid.

1.14 Memory Database

Many applications need to store a considerable amount of data in session objects in units of users, typical applications such as shopping baskets and directories. Since this type of data can be organized in the form of rows/columns, many applications have created a large vector or hashmap. Saving this type of data in a session greatly limits the scalability of the application, because the server must have at least the memory occupied by each session multiplied by the maximum number of concurrent users, it not only makes the server expensive, but also prolongs the time interval for garbage collection to an intolerable level.

Some people transfer the shopping basket/directory function to the database layer, which improves scalability to a certain extent. However, putting this feature on the database layer also has problems, and the root cause of the problem is related to the architecture of most relational database systems. For relational databases, one of the important runtime principles is to ensure that all write operations are stable and reliable. Therefore, all performance problems are related to the ability to physically write data to disks. Relational databases try to reduce I/O operations, especially for read operations. However, the main way to achieve this is to execute a complex algorithm that implements the buffer mechanism, this is the main reason why the performance bottleneck of No. 1 in the database layer is always CPU.

A solution to replace traditional relational databases is to use in-memory databases such as TimesTen. The starting point of the memory database is to allow temporary data writing, but the data does not need to be permanently saved to the disk, and all operations are performed in the memory. In this way, the memory database does not need complex algorithms to reduce I/O operations, and can adopt a simple locking mechanism, so the speed is very fast.

  Iii. Gui

This section is suitable for graphical user interface applications (Applet and common applications) and uses AWT or swing.

3.1 Use jar to compress class files

Java file (JAR file) is a file compressed according to the javajan standard. It is the main method and recommended method for publishing the javajan component. Jar files help reduce the file volume and shorten the download time. For example, it helps the applet increase the startup speed. A jar file can contain one or more related beans, as well as supporting files, such as bitwise, sound, HTML, and other resources.

To specify the JAR file in the HTML/JSP file, you only need to add the archive = "name. Jar" declaration to the applet tag.

3.2 prompt applet Loading Process

Have you ever seen a website that uses an applet and noticed that there is a placeholder in the place where the applet should be run? What happens when the applet is downloaded for a long time? The biggest possibility is that the user turns around and leaves. In this case, displaying the information that an applet is downloading will undoubtedly help to encourage users to continue waiting.

Let's take a look at a specific implementation method. First, create a small applet, which is responsible for downloading the official Applet in the background:

 

Import java. Applet. Applet;

Import java. Applet. appletstub;

Import java. AWT. label;

Import java. AWT. graphics;

Import java. AWT. gridlayout;

Public class preloader extends applet implements runnable, appletstub

{

String largeappletname;

Label label;

Public void Init ()

{

// The formal applet to be loaded

Largeappletname = getparameter ("applet ");

// "Please wait" prompt

Label = new label ("Please wait..." + largeappletname );

Add (Label );

}

Public void run ()

{

Try

{

// Obtain the class of the applet to be loaded

Class largeappletclass = Class. forname (largeappletname );

// Create the instance for which the applet is to be loaded

Applet largeapplet = (applet) largeappletclass. newinstance ();

// Set the stub program of the Applet

Largeapplet. setstub (this );

// Cancel the "Please wait" Message

Remove (Label );

// Set the Layout

Setlayout (New gridlayout (1, 0 ));

Add (largeapplet );

// Display the official Applet

Largeapplet. INIT ();

Largeapplet. Start ();

}

Catch (exception ex)

{

// Display the error message

Label. settext ("the specified applet cannot be loaded ");

}

// Refresh the screen

Validate ();

}

Public void appletresize (INT width, int height)

{

// Transfer the appletresize call from the stub program to the Applet

Resize (width, height );

}

}

The compiled code is less than 2 kb, And the download speed is fast. There are several points worth noting in the code. First, preloader implements the appletstub interface. Generally, the applet judges its codebase from the caller. In this example, we must call setstub () to tell the applet where to extract this information. Another note is that the appletstub Interface contains many methods that are the same as the Applet Class, except for the appletresize () method. Here we pass the call to the appletresize () method to the resize () method.

3.3 pre-mount it before drawing the image

The imageobserver interface can be used to receive prompt information about image loading. The imageobserver interface has only one imageupdate () method. You can use a repaint () operation to draw images on the screen. An example is provided below.

 

Public Boolean imageupdate (image IMG, int flags, int X, int y, int W, int H)

{

If (flags & allbits )! = 0 {repaint ();

}

Else if (flags & (error | abort ))! = 0)

{

Error = true;

// The file is not found. Consider displaying a placeholder

Repaint ();

}

Return (flags & (allbits | error | abort) = 0;

}

The imageupdate () method is called When graphical information is available. If further updates are required, the method returns true. If required information is obtained, the method returns false.

3.4 overwrite the update Method

The default action of the update () method is to clear the screen and then call the paint () method. If you use the default Update () method, applications that frequently use graphs may flash. To avoid the screen cleanup operation before the paint () call, override the update () method as follows:

Public void Update (Graphics g) {paint (g );}

The ideal solution is to overwrite Update () and only redraw the area on the screen that has changed, as shown below:

  

Public void Update (Graphics g)

{

G. cliprect (X, Y, W, H );

Paint (g );

}

3.5 delayed re-painting

For graphic user interface applications, the main reason for poor performance can often be attributed to the inefficiency of the screen. This is usually observed when the user changes the window size or scrolls a window. Operations such as changing the window size or scrolling the screen cause a large number of screen re-painting events to be generated quickly, or even exceed the execution speed of the relevant code. The best way to deal with this problem is to ignore all "late" events.

It is recommended to introduce a time difference of several milliseconds here, that is, if we receive another re-painting event immediately, we can stop processing the current event and then process the last re-painting event received; otherwise, we continue the current re-painting process.

If an event needs to start a time-consuming task, separating a working thread is a good way to handle it. Otherwise, some parts may be frozen because only one event can be processed at a time. The following provides a simple example of event processing, but after expansion, it can be used to control the working thread.

 

  

Public static void runonce (string ID, final long milliseconds)

{

Synchronized (e_queue)

{

// E_queue: a collection of all events

If (! E_queue.containskey (ID ))

{

E_queue.put (token, new lastone ());

}

}

Final lastone = (lastone) e_queue.get (token );

Final long time = system. currenttimemillis ();

// Obtain the current time

Lastone. Time = time;

(New thread ()

{

Public void run ()

{

If (milliseconds> 0)

{

Try

{

Thread. Sleep (milliseconds );

}

// Pause the thread

Atch (exception ex ){}

}

Synchronized (lastone. Running)

{

// Wait until the last event ends

If (lastone. Time! = Time)

// Only process the last event

Return;

}

}). Start ();

}

Private Static hashtable e_queue = new hashtable ();

Private Static class lastone

{

Public long time = 0;

Public object running = new object ();

}

3.6 use dual-Buffer

The entire image is displayed immediately after the drawing is completed in the buffer area outside the screen. Because there are two buffers, the program can switch back and forth. In this way, we can use a low-priority thread to draw pictures, so that the program can use idle CPU time to execute other tasks. The following pseudocode snippets demonstrate this technology.

  

Graphics mygraphics;

Image myoffscreenimage = createimage (SIZE (). Width, size (). Height );

Graphics offscreengraphics = myoffscreenimage. getgraphics ();

Offscreengraphics. drawimage (IMG, 50, 50, this );

Mygraphics. drawimage (myoffscreenimage, 0, 0, this );

3.7 Use bufferedimage

Java JDK 1.2 uses a soft display device to make the text look similar on different platforms. To implement this function, Java must directly process the pixels that constitute the text. Because this technology requires a large amount of bit replication operations in the memory, early JDK was not performing well when using this technology. The java standard proposed to solve this problem implements a new graphic type, namely bufferedimage.

The image described by the bufferedimage subclass has an accessible graphic data buffer. A bufferedimage contains a colormodel and a set of Raster Graphic Data. This class uses RGB (red, green, and blue) color models, but it can also process grayscale images. Its constructor is very simple, as shown below:

Public bufferedimage (INT width, int height, int imagetype)

Imagetype allows us to specify the types of images to buffer, such as 5-bit RGB, 8-bit RGB, and grayscale.

3.8 Use volatileimage

Many hardware platforms and their operating systems provide basic hardware acceleration support. For example, hardware acceleration generally provides the rectangle filling function, which is more efficient than using the CPU to complete the same task. Hardware acceleration separates some of the work and allows multiple workflows to run concurrently. This reduces the pressure on CPU and system bus and enables applications to run faster. Volatileimage allows you to create a hardware-accelerated image and manage its content. Because it directly utilizes the capabilities of the lower-layer platform, the performance improvement mainly depends on the graphic adapter used by the system. Volatileimage content may be lost at any time, that is, it is "unstable )". Therefore, before using a graphic, it is best to check whether its content is lost. Volatileimage has two methods to check whether the content is lost:

Public abstract int validate (graphicsconfiguration GC); Public Abstract Boolean contentslost ();

The Validate () method should be called each time the content is copied from the volatileimage object or written to the volatileimage object. The contentslost () method tells us whether the image content is lost since the last validate () call.

Although volatileimage is an abstract class, do not derive a subclass from it. Volatileimage should be created using the component. createvolatileimage () or graphicsconfiguration. createcompatiblevolatileimage () method.

3.9 Use Window blitting

During the scrolling operation, all visible content must be repainted, resulting in a large amount of unnecessary re-painting. The graphic subsystems of Many operating systems, including Win32 GDI, MacOS, and X/windows, all support the window blitting technology. Window blitting technology directly moves the image to a new position in the screen buffer, and only re-draws the new area. To use the window blitting Technology in swing applications, the configuration method is as follows:

Setscrollmode (INT mode );

In most applications, this technology can improve the rolling speed. In only one case, window blitting may result in lower performance, that is, the application performs rolling operations in the background. If the user is rolling an application, it is always on the frontend without worrying about any negative impact.

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.