Improved object management methods in Java, improve program performance

xiaoxiao2021-03-06  112

Object management improvement program to improve the performance of: cactus studio herein are selected from: a SEOUL, Java memory management March 26, 2002

Objects are powerful software constructors, which have extremely widely used in Java. In fact, because the application of the object is so wide, developers sometimes forget the cost of creating an object, resulting in the program to enter the "Object Churn) state. In this state, most of the processor is consumed to create objects and recycled objects of the abandoned object at the time of initiating.

For developers familiar with C / C , the simplification of memory management is an important feature of Java. In contrast, Java allows developers to allocate space as needed, and ensure that the space occupied by JVM as needed to be used as needed, and ensure that the space occupied by the JVM. These tasks are carried out in the spam in the spam in the background.

In the programming language, the garbage collection mechanism is used to manage memory to retroct to the computer that has just been born in the 1960s. Regardless of the specific situation, the basic principles of garbage collection are the same: first identify the objects that the programs are no longer used, and then reclaim the memory occupied by these objects.

Generally, JVM uses a "reachability algorithm to identify the object being used, and then reclaim all the rest of the object. This process begins with variables directly used by a group of programs, including local variables of each active thread, and call the parameter variables on the stack and the objects referenced by the static variables that have been loaded. The objects cited by all of the above variables are added to the "reachable" object collection. Next, each object referenced by the member variables of these objects is also added to the reachable object set. This process is repeated until the end; each object referenced by any object reaches an object collection is already in a collection. All objects that are not reachable objects are considered to be discarded, that is, can be safely recovered.

Typically, Java's garbage collection process does not require developers intervention. The JVM periodically runs the garbage collection process, or when the program thread is waiting for external events, it allows the garbage collection process to run; or when the program creates a new object, it is insignificant, so it must run the garbage collection process. Although garbage collection is automated, it is important to understand this process because garbage collection will take up a large part of the JAVA program overhead.

In addition to the time overhead of garbage collection, the objects in Java also produce a large amount of space overhead. For each assigned object, the JVM will add the necessary internal information to carry out the garbage collection process. In addition, JVM also adds information required by the Java language norm, which is essential for some functions, such as synchronizing on arbitrary objects. If the JVM is included in the space for each object, the small Java object is much larger than that of C / C . The following table shows the memory usage of several simple objects, where the "Content" column shows the size of the user to access the content, and the remaining columns show the actual memory size of the object under different JVM, from which Out of additional memory overhead of JVM.

Content (number of bytes) JRE 1.1.8 * (SUN) JRE 1.1.8 (IBM) JRE 1.2.2 (Classic) JRE 1.2.2 (Hotspot 2.0 Beta) java.lang.object 0 26 31 28, Java.lang .INTEGER 4 26 31 28 26 INT [0] 4 26 31 28 26 Java.lang.String (4 characters) 8 4 58 63 60 58 The above space overhead is the value of a single object, so for large objects The percentage of space overhead will drop. If the program uses a large number of small objects, it may make performance very bad.

Second, try to use the basic data type

In the Java program, the easiest policy to reduce object creation operations may be as used as possible to use the basic data type. However, this strategy can be applied, not many applications, many times the object has sufficient reason to become the preferred data format, simply use the basic data type to replace the object to meet the design requirements. However, it can reduce a lot of overhead in an occasion of this strategy.

Java's basic data types include Boolean, Byte, Char, Double, Float, Int, long, and short. Variables using basic data types do not generate the overhead of the creation of objects, and do not need garbage collection after running. For local method variables, the JVM will allocate variable space directly in the stack; for member variables, JVM uses the space used in the object to allocate space.

Java defines the corresponding package classes for each basic data type. The package is represented by the basic data type value, which makes the value of the basic data type can be treated as an object; using java.util.Vector, java.util.stack, java.util.hashtable and other tool classes This object is very useful. However, in addition to these special circumstances, avoid using package classes, try to use basic data types to avoid creating memory and time overhead required to create objects.

In addition to standard package categories, there are some classes in the Java class library to plus a new semantic and behavior, java.util.date, and java.awt.point belong to such an example. In a large number of applications, store and transfer the corresponding basic type values ​​(only when necessary, they can reduce unnecessary object creation operations. For example, for the Point class, we can directly access the int value inside the POINT, or combine them into a long value such that the method call simply returns a basic type of value. Here is an example of a calculation:

... // uses the long value to represent the POINT example. / / The high position of each long value contains the X coordinate, // low inclusion contains Y coordinate public long Midpoint (long a, long b) {// calculate the median INT x = (int) on each coordinate ((((A>) > 32) (B >> 32)) / 2); int y = (int) a (int) b) / 2; // Returns the midpoint return (x << 32) y;} .. .

Third, dedicated object reuse

Reducing an object to create an operation is a reuse object. The reused object may be designed for a particular purpose, or may be used in different purposes at different times, and therefore, the retrimabel mainly includes two modifications: dedicated object reuse, with simple and convenient features; free buffer pool Reuse, with the best object reuse effect. The simplest object reuse is that a frequently executed task requires one or more access to an auxiliary role. Many applications often format the date of formatting, and we will discuss the dedicated object reuse as an example. To use a specified date value (as required as much as possible as possible, this value is a long type) Generates the default string representation, we can:

... // The default string representation of the generation time represents long time = ...; string display = DateFormat.getdateInstance (); format (new date (time)); ...

This statement looks very simple, but in fact, a large amount of complex object creation operations are conducted. DateFormat.getDateInstance () Calls a new SimpleDateFormat instance, the latter to create a series of related objects; then, the Format calls to create new StringBuffer and FieldPosition objects. Under JRE 1.2.2 and Windows 98, this simple statement actually allocates up to 2400 bytes. If this statement needs to perform frequently, the number of objects that temporarily generate and discarding is considerable.

3.1 Private objects

The improved method is to pre-(dispose) to create the object required to format, which is owned (dedicated) by using the code using them, and then these objects are required. For example, if we implemented this scheme through an instance variable, each instance of the container class has the only copy of these objects, and the modified code is as follows:

... // Date format objects allocated in the form of a dedicated member variable private final Date convertDate = new Date (); private final DateFormat convertFormat = DateFormat.getDateInstance (); private final StringBuffer convertBuffer = new StringBuffer (); private final FieldPosition Convertfield = new fieldPosition (0); ... // Generate the default string representation of the specified date LONG TIME = ...; convertDate.settime (time); convertBuffer.setlength (0); stringbuffer output = DateFormatter.Format (ConvertDate, ConvertBuffer, Convertfield); String Display = Output.toString (); ...

This code snippet obviously is longer than the original code, but only the output string object is required at each execution, so the speed is much faster. Simple test shows that the improved code 100,000 iterations take only 8 seconds, and the corresponding time of the code is 50 seconds. Since the object used to format is not released immediately after use, the improved code takes up more memory (or longer occupying time), but if the code is executed very frequently, this cost is still very comparable. It is worth noting that if there is an internal loop within a method to perform a large number of iterations, the techniques discussed above are equally useful. We do not have to transfer objects used in the loop to the class containing the method, but can move the creation of these objects to the loop, so that the creation operation is only executed once. According to this idea, the code can be:

// Distribute the object Date Date = new date (); DateFormat Formatter = DateFormat.getDateInstance (); stringbuffer buffer = new stringbuffer (); infinposition field = new fieldPosition (0); // Perform a loop for ...) {// String representation of the specified time Representation LONG TIME = ...; Date.SetTime (TIME); buffer.setlength (0); stringbuffer output = formatter.format (Date, Buffer, Field); String display = output.toString ();

Combined with the previously described basic type value replaces the corresponding object type value technology, this dedicated object retro technology is better. A dedicated object can be instantiated from the basic type value and then passed to the Java standard class library requires the object as a method of parameter type. The above dedicated DATE object is a good example.

3.2 Multiple thread utilities private objects

Suppose we have a group of private objects, with multiple threads to perform code that uses these objects, so you must avoid conflicts that different threads can operate. The easiest way to implement this object is to specify one of the objects as a lock of the entire group, encapsulate the code used to use these objects in a block synchronized on the lock object. Although the overhead of the lock operation is increased each time, the opening of the lock operation is smaller than the time of creating an object.

Assuming to use the CONVERTDATE object as a lock, the code used to use these objects should be changed to: // Get the user's use right synchronized (convertDate) {// Get the default string representation of the specified time = ...; convertdate. SetTime (TIME); ConvertBuffer.setlength (0); StringBuff Output = Dateformatter.Format (ConvertDate, ConvertBuffer, Convertfield); string display = output.toString ();}

If the code using a private object is always running in a single thread, it is no longer necessary. However, the code is more flexible after increasing the locking mechanism. For example, in the previous example, we created an instance variable for private objects, that is, instances of each container class contain such an object. When the transfer of private objects is extremely frequent, every instance of the container class must configure this group of private objects in different ways, we should use instance variables. However, if the call to the private object is not particularly frequent, it is not necessary to customize these private objects for each instance of the container class, so that the class itself has these objects may be better. To this end, we only need to specify the member variable as static:

. = DateFormat.getDateInstance (); private static final StringBuffer convertBuffer = new StringBuffer (); private static final FieldPosition convertField = new FieldPosition (0); ... // get the right to use synchronized (convertDate) {// get private objects designated default string representation of the date long time = ...; convertDate.setTime (time); convertBuffer.setLength (0); StringBuffer output = dateFormatter.format (convertDate, convertBuffer, convertField); string display = output.toString () } ...

This method has both a dedicated object retrospective technology at a speed advantage, and a total of memory between all instances of such classes.

Fourth, the buffer pool object is reused

The buffer pool is another way of object reuse. When using this object reuse, if the object used by the program belongs to the buffered type, it must explicitly return the object to the buffer pool after the use is completed. Buffer pool collects reusable objects, adds objects released to reusable objects; when program requests object, the buffer pool removes from the reusable object set and reinitializes an object, not recreated an object. The buffer pool creates a new object only if the available object is set to be empty.

Maintaining the management overhead of a collection of available objects The performance improvement of this object reuse is weakened, however, this technology is still useful in those environments that frequently reuse specific types of objects. Below we will discuss various methods for managing the collection of available objects, and understand the applicable occasions of each method in depth by practice.

4.1 Universal Buffer Pool

The construction and management of the buffer pool can be implemented in a variety of ways. The most flexible way is to be buffered to specify the type of buffer pool, and a possible implementation is as follows:

import java.lang *;. import java.util *;. public class ObjectPool {private final Class objectType; private final Vector freeStack; public ObjectPool (Class type) {objectType = type; freeStack = new Vector ();} public ObjectPool ( Class type, int size) {ObjectType = type; freestack = new vector (size);} public synchronized Object getInstance () {// Check the buffer pool is empty if (FreeStack.isempty ()) {// Such as buffer pool space, Create a new object try {return ObjectType.newinstance ();} catch (iLlegalaccessException ex) {} throw new runtimeException ("Anomalus when creating a new instance");} else {// Cushion The end of the pool is removed from Object Result = freeESTACK.lastelement (); freeStack.Size () - 1); return result;}} public synchronized void FreeInstance (Object obj) { / / Make sure the object has the correct type if (ObjectType.isinstance (obj)) {freeestack.addelement (obj);} else {throw new illegaluntexception ("The buffer pool cannot buffer the specified object type");}}} Use a Java.util.Vector as an extensible buffer pool. ObjectPool constructor requires the Class type to be buffered (you can also specify the size of the buffer pool, optional). When a new object is added to the buffer pool, it will check if the object's type is correct. When there is no longer available object in the buffer pool, it will create and return an instance of the buffered object type.

For example, suppose we write a process of processing a graphics to use a large number of rectangles. Due to frequently created a short-term java.awt.Rectangle object increases a lot of overhead, using ObjectPool classes to easily avoid the overhead of this type of creation of objects:

// Create a shared buffer pool for the Rectangle object private static final ObjectPool rectanglePool = new ObjectPool (Rectangle); ... // create a Rectangle object Rectangle rect = (Rectangle) rectanglePool.getInstance (); rect.height = height; Rect.width = width; rest.x = x; rest.y = y; ... // Return the Rectangle object to the buffer pool RectanglePool.FreeInstance (Rect); although this buffer pool is used up, but Unfortunately, the above code is slower than direct creating Rectangle objects! All additional code (especially a large number of types of types (CAST) operations, plus synchronization of the VECTOR class, so that the time of the use of the buffer pool uses the object to directly assign and release the object mode.

It should be noted that the test of the above result is biased towards the way the object is directly distributed and released without the buffer pool, as its rectangle instance is very short, and the number of other objects in the program is less than the lowest limit ( Thus the work efficiency of the garbage collector reaches the highest. However, this test results show that even in the most ideal case, this buffer pool has also been very limited in performance; in the worst case, the performance of the program is reduced. This buffering mode is highly high, and is more effective for object buffer pools used to control resources (such as database connections). However, in order to further reduce the overhead of allocation objects, we also need a fast-moving object buffer pool.

4.2 Built-in buffer pool

The management overhead of the general buffer pool ObjectPool is too large, and most of the advantages of reuse objects have been offset. General code often exists such problems: Although they achieve code reuse, it is usually accompanied by performance losses.

To resolve the problem facing ObjectPool, we can directly construct the object buffer pool directly into the object to be buffered. That is to say, define a class with the Rectangle equivalent but with the buffer pool (for simple meter, we define it as a fixed size):

import java.awt *;. import java.lang *;. import java.util *;. public class ImmutableRectangle {private static final int FREE_POOL_SIZE = 40; // // buffering capacity pool owned by the class private static final ImmutableRectangle [] freeStack = new ImmutableRectangle [FREE_POOL_SIZE]; private static int countFree; // represents a member variable state private int xValue; private int yValue; private int widthValue; private int heightValue; private ImmutableRectangle () {} public static synchronized ImmutableRectangle getInstance (int x , int y, int width, intang {// check if the buffer is emmutablerectangle result; if (countfree == 0) {// If the buffer is empty, create a new object Result = new immutableRectangle ();} else {// remove an object result = freestack [- countfree] from the end of the buffer,} // initialize the object to the specified state Result.xValue = x; Result.yValue = Y; Result.WidthValue = Width; Re sult.heightValue = height; return result;} public static ImmutableRectangle getInstance (int width, int height) {return getInstance (0, 0, width, height);} public static ImmutableRectangle getInstance (Point p, Dimension d) {return getInstance ( px, py, d.width, d.height);} public static ImmutableRectangle getInstance () {return getInstance (0, 0, 0, 0);} public static synchronized void freeInstance (ImmutableRectangle rect) {if (countFree

} Public int getWidth () {Return WidthValue;} PUBLIC INT GetHEight () {Return HeightValue;}} We can get reusable objects. Compared to the method of distributing recycled reuse, the performance performance of the new method is also improved even for Rectangle's simple objects. For complex objects, performance improvement is more obvious.

If the object in the buffer pool is for use only, there is a further improvement of performance. At this time, the GetInStance () and FreeInstance () methods can be used to make performance than allocating recycling of several times higher than the Synchronized keyword. However, it should be noted that the buffer pool at this time lacks thread safety.

This feature is achieved by the buffer pool to reuse: After using the object, the code to use the object must return the object to the buffer pool. From some aspects, this seems to be re-returned to C / C , that is, the program explicitly participates in the allocation and release process. However, different from C / C is that we can choose to manage object management in which places in the form of buffer pools in Java. For objects that use frequencies in programs, the management strategy of explicitly assign and release objects will be greatly advantageous to improve performance.

In addition, this type of buffer pool is much more than C / C "tolerance". Once an unexpected situation, that is, the object has not been returned to the buffer pool. The only impact is slightly lowered - when the program no longer uses an object, this object will eventually be recycled as garbage, we only need to be appropriate When you reassign an object. In C / C , the object that is not released has been existed during the program survival, resulting in a memory vulnerability that may cause the C / C program to crash. The object pool is often used to manage some limited (or expensive) resources, such as database connections. This type of buffer pool may not be so beaten. If the resource is not released correctly, it will not be reused before restarting the JVM.

[Conclusion]: In this article, we analyzed some Java object management issues, discussed several technologies that effectively reduce objects to create operations and garbage recycling operations. However, please pay attention to the following points before applying some kind of optimization technology in the program:

Do not optimize for optimization, only the optimization can only be proven to be optimized. Use effective timing techniques or reliable execution analyzers to find specific performance issues, and then optimize.

Optimization should be carried out carefully; otherwise, new bugs may be introduced. Remember, slower but stable code ratio speed although fast but unstable code is better.

After optimization, use the appropriate tool to analyze the code again to ensure optimization has reached the expected results. This step is especially important when optimization is a system with multiple modules sharing the optimized portion.

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

New Post(0)