Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Design for performance, Part 2: Reduce object creation - JavaWorld February 2001

Design for performance, Part 2: Reduce object creation - JavaWorld February 2001

Tutorial Details:

Design for performance, Part 2: Reduce object creation
Design for performance, Part 2: Reduce object creation
By: By Brian Goetz
Avoid performance hazards while designing Java classes
hough many programmers put off performance management until late in the development process, performance considerations should be integrated into the design cycle from day one. This series explores some of the ways in which early design decisions can significantly affect application performance. In this article, I continue to explore the problem of excessive temporary object creation and offer several proven techniques for avoiding their creation.
Read the whole "Design for Performance" series:
Part 1: Interfaces matter
Part 2: Reduce object creation
Part 3: Remote interfaces
Temporary objects are those that have a short lifetime and generally serve no useful purpose other than to act as containers for other data. Programmers generally use temporary objects to pass compound data to -- or return it from -- a method. Part 1 explored how temporary object creations could have a serious negative impact on a program's performance and showed how certain class interface design decisions virtually guarantee temporary object creation. By avoiding those interface constructs, you can dramatically reduce the need to create temporary objects that can sap your program's performance.
Just say no to String?
When it comes to creating temporary objects, the String class is one of the biggest offenders. To illustrate that, in Part 1 I developed an example of a regular expression-matching class and showed how a harmless-looking interface imposed enough object-creation overhead to make it run several times slower than a similar class with a more carefully designed interface. Here are the interfaces for both the original and the better-performing classes:
BadRegExpMatcher
public class BadRegExpMatcher {
public BadRegExpMatcher(String regExp);
/** Attempts to match the specified regular expression against the input
text, returning the matched text if possible or null if not */
public String match(String inputText);
}
BetterRegExpMatcher
class BetterRegExpMatcher {
public BetterRegExpMatcher(...);
/** Provide matchers for multiple formats of input -- String,
character array, and subset of character array. Return -1 if no
match was made; return offset of match start if a match was
made. */
public int match(String inputText);
public int match(char[] inputText);
public int match(char[] inputText, int offset, int length);
/** If a match was made, returns the length of the match; between
the offset and the length, the caller should be able to
reconstruct the match text from the offset and length */
public int getMatchLength();
/** Convenience routine to get the match string, in the event the
caller happens to wants a String */
public String getMatchText();
}
Programs that heavily use BadRegExpMatcher will run slower than those using BetterRegExpMatcher . First, callers have to create a String object to pass into match() , which then has to create another String object to return the matched text to the caller. That results in at least two object creations per invocation, which may not sound like much, but if you call match() frequently, the performance overhead of those object creations can really add up. The problem with BadRegExpMatcher 's performance is not in its implementation but in its interface; with the interface defined as it is, there is no way to avoid creating several temporary objects.
BetterRegExpMatcher replaces the String objects in match() with primitive types (integers and character arrays); no intermediate objects need to be created to pass information from the caller to match() and back.
Since it is generally easier to avoid performance problems at design time than to fix them after you've written your entire program, you should watch out for the ways in which your class interfaces might mandate object creation. In the case of RegExpMatcher , the fact that its methods require and return String objects should provide a warning sign for potential performance hazards. Since the String class is immutable, all but the most trivial processing of a String argument will require the creation of a new String for every invocation.
Is immutability necessarily bad for performance?
Because String is so commonly associated with excessive object creation, which is generally ascribed to its immutability, many programmers assume that immutable objects are inherently bad for performance. However, the truth is somewhat more complicated. Actually, immutability can sometimes offer a performance advantage, and mutable objects can sometimes cause performance problems. Whether mutability is helpful or harmful for performance depends on how the object is used.
Programs frequently manipulate and modify text strings -- which is a bad match for immutability. Every time you want to manipulate a String -- like finding and extracting a prefix or substring, converting it to upper- or lowercase, or combining two strings into a new one -- you must create a new String object. (And in the case of concatenation, the compiler creates a hidden temporary StringBuffer object, too.)
On the other hand, a reference to an immutable object can be freely shared without having to worry that the referenced object will be modified, which can offer a performance advantage over mutable objects, as the next section illustrates.
Mutable objects have their own temporary object problems
In the RegExpMatcher example, you saw that when a method had a return type of String , it usually necessitated the creation of a new String object. One of the problems with BadRegExpMatcher was that match() returned an object rather than a primitive type -- but just because a method returns an object, doesn't mean that a new object must be created. Consider the geometry classes in java.awt such as Point and Rectangle . A Rectangle is just a container of four integers (x, y, width, and height). The AWT Component class stores the component location and returns it as a Rectangle through the getBounds() accessor method:
public class Component {
...
public Rectangle getBounds();
}
In the example above, the getBounds() method is really an accessor -- it simply makes available some state information that is internal to Component . Does getBounds() have to create the Rectangle it will return? Maybe. Consider this possible implementation of getBounds() :
public class Component {
...
protected Rectangle myBounds;
public Rectangle getBounds() { return myBounds; }
}
When a caller calls getBounds() in the above example, no new objects are created -- since the component already knows where it is -- so getBounds is quite efficient. However, Rectangle 's mutability creates other problems. What happens when a caller executes the following?
Rectangle r = component.getBounds();
...
r.height *= 2;
Because Rectangle is mutable, it causes the component to move without Component 's knowledge. For a GUI toolkit such as AWT, that would be a disaster because, when a component is moved, the screen needs to be redrawn, event-listeners need to be notified, etc. So the code above seems a dangerous way to implement Component.getBounds() . A safer implementation of Component would implement getBounds() as follows:
public Rectangle getBounds() {
return new Rectangle(myBounds.x, myBounds.y,
myBounds.height, myBounds.width);
}
But now, each call to getBounds() creates a new object, just as RegExpMatcher did. In fact, the following code fragment creates four temporary objects:
int x = component.getBounds().x;
int y = component.getBounds().y;
int h = component.getBounds().height;
int w = component.getBounds().width;
In the case of String , the object creations were required because String is immutable. But in this case, an object creation seems to be required because Rectangle is mutable . We avoided the problem with String by not using any objects in our interfaces. While that worked in the case of RegExpMatcher , that solution is not always possible or desirable. Fortunately, you can employ several techniques when designing classes that allow you to rid yourself of the too-many-small-objects problem without avoiding small objects altogether.
Object-reduction technique 1: Add finer-grained accessor functions
In initial versions of the Swing toolkit, the creation of many temporary Point , Rectangle , and Dimension objects seriously hampered performance. While it appeared more efficient to return multiple values at once by containing them in a Point or Rectangle , the object creation was, in fact, more expensive than multiple method calls. Before the final release of Swing, that problem was ameliorated quite simply by adding some new accessor methods to Component and other classes, such as the following:
public int getX() { return myBounds.x; }
public int getY() { return myBounds.y; }
public int getHeight() { return myBounds.height; }
public int getWidth() { return myBounds.width; }
Now a caller can retrieve the bounds with no object creations such as this:
int x = component.getX();
int y = component.getY();
int h = component.getHeight();
int w = component.getWidth();
The old form of getBounds() is still supported; the finer-grained accessor functions simply provide a more efficient way to complete the same objective. In effect, the interface of Rectangle has been fully exposed in the Component interface. When the Swing package was modified to support and use those finer-grained accessor functions, it resulted in many Swing operations performing nearly twice as fast as they had previously. That was significant, as GUI code is highly performance-critical -- the user waits for something to happen and indeed expects UI operations to be instantaneous.
The downside of using that technique is that your objects now have more methods and more than one way to retrieve the same


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Design for performance, Part 2: Reduce object creation - JavaWorld February 2001

View Tutorial:
Design for performance, Part 2: Reduce object creation - JavaWorld February 2001

Related Tutorials:

Java memory management
Java memory management
 
Connect the enterprise with the JCA, Part 1
Connect the enterprise with the JCA, Part 1
 
A birds-eye view of Web services
A birds-eye view of Web services
 
Cache SOAP services on the client side
Cache SOAP services on the client side
 
I want my AOP!, Part 3
I want my AOP!, Part 3
 
Good introduction to JDO
Good introduction to JDO
 
J2SE 1.4 breathes new life into the CORBA community, Part 2
J2SE 1.4 breathes new life into the CORBA community, Part 2
 
Business process automation made easy with Java, Part 2
Business process automation made easy with Java, Part 2
 
Should you go with JMS?
Should you go with JMS?
 
J2SE 1.4 breathes new life into the CORBA community, Part 3
J2SE 1.4 breathes new life into the CORBA community, Part 3
 
Attack of the clones
Attack of the clones
 
Navigate through virtual worlds using Java 3D
Navigate through virtual worlds using Java 3D
 
Create client-side user interfaces in HTML, Part 2
Create client-side user interfaces in HTML, Part 2
 
Worth reading
Worth reading
 
XStream
XStream is a simple library to serialize objects to XML and back again.
 
An Intelligent Nim Computer Game, Part 1
An Intelligent Nim Computer Game, Part 1 In this article, you learn how to play Nim, and discover tools for creating an intelligent computer player. In the next article, you apply those tools to the creation of that player, while building console and G
 
JLAN Server v3.3
JLAN Server v3.3 JLAN Server is a high performance JavaTM based file server supporting Windows file sharing (SMB/CIFS), NFS and FTP protocols. Write your own virtual filesystems with the core server handling all protocol exchanges with the client. Incl
 
Definition of Bioinformatics
Definition of Bioinformatics Definition of Bioinformatics About Bioinformatics In February 2001, the human genome was finally deciphered! In other words, scientists have succeeded in reading the chain of more than 3 billion base pairs that
 
What is Persistence Framework?
What is Persistence Framework? What is Persistence Framework? A persistence framework moves the program data in its most natural form (in memory objects) to and from a permanent data store the database. The persistence framework manages the
 
Solaris 10 OS Certification Beta Exams
If you are an expert in system and network administration, you can get involved in the creation of three new Solaris 10 certification exams. These Beta exams count toward official Solaris Certification and allow you to provide comments and technical feedb
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.