Java Performance Tuning
Java(TM) - see bottom of page
Our valued sponsors who help make this site possible
JProfiler: Get rid of your performance problems and memory leaks!
Training online: Concurrency, Threading, GC, Advanced Java and more ...
Newsletter no. 13, December 26th, 2001
JProfiler
|
Get rid of your performance problems and memory leaks!
|
JProfiler
|
Get rid of your performance problems and memory leaks!
|
|
|
As promised, I've started categorizing the tips at the website. If
you go over to the tips page, you'll see that there is a new format.
The old tips page is still accessible (as rawtips), but I'm
categorizing every tip and each category will result in a page
containing only the tips for that category. I'll add a new category
about twice a month. The initial two categories are JDBC and
synchronization.
Now on with the news. This month we have a bumper crop of URLs.
I guess everyone is trying to get out their articles before the
holiday season. JDBC certainly seems to have come of age. The
experienced tips being written are one indication of that, but
the clincher is a new book called "Oracle JDBC" - specialization
within specialization.
Other than that, we have J2EE articles (mainly EJB but other aspects
too, not forgetting that JDBC is also a component of J2EE); a variety
of other articles, some more chapters from "Java Platform Performance"
and pages from another recently built Java performance focused website,
precisejava.com. That's Ravi Kalidindi trying to steal my thunder:
competition for me, more information for you. Fortunately, I learned
a long time ago that if you don't have any competition, the field
can't be worth much, so I'm actually delighted to see another website
dedicated to Java performance.
As usual Kirk follows the discussion groups, with one discussion in
particular, on microbenchmarks, generating significant coverage. Note
that I've added an index into Kirk's roundup from the main newsletter
page so that you can reach it directly if that's where you like to
start.
And here's my usual reminder to our Japanese readers that
Yukio Andoh's translation should be available at
http://www.hatena.org/JavaPerformanceTuning/ in a while.
News
Java performance tuning related news.
Upcoming
- There should be a couple more category pages next month.
- And I will continue extracting tips from more chapters of Wilson & Kesselman's book.
Links
Tools
Recent Articles
All the following page references have their tips extracted below.
Older Pages
All the following page references have their tips extracted below.
Jack Shirazi
The question of micro benchmarks and micro performance tuning
continues to be a very common topic of discussion in many different
forums. Most recently, there was a posting to one of the lists concerning
the cost of of casts. The poster described how he had always used
the toString() method when retrieving String objects from a HashMap
instead of casting. One day he got curious and wrote a micro
benchmark to empirically compare the two techniques. In his post,
he supplied both source and some results. Everyone who responded
to his posting suggested that one should never run a micro benchmark.
(The String.toString() method, shown here, is pretty simple. It causes
an Object to narrow to a String without explicity needing a cast.)
/**
* This object (which is already a string!) is itself returned.
*
* @return the string itself.
*/
public String toString() {
return this;
}
Some responders quite correctly pointed out that tuning efforts should be
saved for application bottlenecks. But, this point only shows that there
is some confusion concerning the difference between macro and micro
performance tuning and benchmarking. Other performance tuning experts
consider that micro benchmarks produce erroneous and consequently misleading
results. Many valid points against microbenchmarks were raised,
including that a micro benchmark
can totally mislead the compiler, HotSpot and JITs. These tools may
make decisions that differ quite significantly from the decisions they
would make when analyzing a real application. It can be difficult to
reproduce real life while conducting a micro benchmark. Since so many
people stand against the validity of micro benchmarks, does this mean
that one should automatically ignore this technique? While it maybe
difficult to reproduce real life in a micro benchmark, it is clearly
not impossible. Given the potentially valuable information concerning
the performance that a particular algorithm or coding style may
produce, it is my opinion that it would be a mistake to ignore this
technique.
Consider the role of a compiler. It's job is to turn your code into
byte code. To carry out this translation, the compiler must understand
what it is that you are trying to do. The easier it is for the compiler
to understand your code, the better chance it has to produce better
byte code (i.e. optimize it). Thus, your coding style can make or
break a compiler's ability to produce optimal byte code. But, what
constitutes a good coding style? Micro benchmarks can help answer this
question.
However, one must be aware of the pitfalls. Lets use the toString()
vs. String cast example to demonstrate. The following code fragment
is an implementation of a micro benchmark:
long start = System.currentTimeMillis();
//
for( i=0; i < 1000000; i++) {
String s = map.get(key).toString();
}
//
long finished = System.currentTimeMillis();
System.out.println(finished - start);
//
start = System.currentTimeMillis();
for (i=0; i < 1000000; i++) {
String s = (String)map.get(key);
}
finished = System.currentTimeMillis();
System.out.println(finished - start);
On the surface, it would appear that this code fragment will
answer the question of which technique is faster. But, on closer inspection,
some doubts should begin to appear. For starters, the code is much more
compact than it would be in a real application. Does this allow the compiler
to make some optimizations that would not exist in a real application?
What about the String declaration inside the first loop. Will that result in
a timing difference? Most sensible compilers will move the declaration out of
the loop, does yours? Some compilers may recognize that the body of the loops
only need to be executed once and may optimize away the loop.
We also have to consider that with Java, the story doesn't end with
the compiler. One must consider the effects of HotSpot and JITs. Again, will
the code in the micro benchmark be optmized differently than that found
in an application? If the code is optimized differently, does it matter?
Lets again turn to our original question and see if a micro benchmark can
provide the answer. I wrote 3 different versions of the original micro
benchmark: the code is listed at the end of the roundup.
In the end, I could find no real difference between the code that
performed an explicit cast and the code that called the toString()
method. I used the JDK version 1.3.0-C. The posted results for the
JDK 1.3.1 were 270ms for the toString() and 251ms for the cast. The
results for the JDK 1.2.2, were 1512ms for the toString() and 1552ms
for the cast. Since I find code that contains explicit casts easier
to read, I'd opt for that coding style rather than make the method call.
While it is true that micro benchmarks are fraught with difficulties,
done carefully, they still can provide useful information that can
have an effect on your coding style. As I was once told by one of the
best performance tuning guru's that I know, "you can fill a water tower
with a tea spoon".
Now onto the discussion groups. This month, we will start with the
Java Ranch.
Readability is amongst the primary motivations for using constants.
So, is there a performance impact from using constants (those fields
declared static final)? Since the compiler will inline anything that
it can resolve at compile time, the answer is there is not.
Last month, I wrote about the discussion regarding initializating fields
to null. Well, the discussion continued and evolved into an even more
interesting discussion focusing on objects, object references, where they
live and when and what effect this has on garbage collection. The term "object"
is overloaded so much that it is easy to confuse even experts. Thus we need
to be mindfull that when one talks about an object, they may actually be
referring to a reference to that object. All non-primitive variable declarations, be they
field, static, local, or method parameters are object references. Objects
exist only in heap space. Fields will be stored in heap space as an object
reference. Local variables, method parameters and return values are object
references that are stored on the stack. How does this effect GC? The rule
is, an object is eligible for GC when it is no longer referenced. Consequently,
we can determine when an object will be eligible for GC. But, how the execution
stack is implemented in the VM is up to the JVM developers. Although we may
reason than local variables and method parameters become eligible for GC as
soon as a method returns, in reality, this is an implementation detail for the
JVM implementors and is beyond our control. If a local variable is large enough,
it maybe wise to set it's object reference to null before the method return.
Just before press, another interesting garbage collection discussion appeared.
The poster has an application that consumes many URLConnection and BufferedReader
objects. For some reason, the application is throwing an OutOfMemoryException
which of course halts the JVM. The local sheriff offered some great advice on
how to track GC related memory problems.
- Use the -verbose:gc option to monitor gc activity.
- Add diagnostic print statements when large objects are allocated and released.
- The output of -verbose:gc isn't guaranteed to be exact but it's generally close
enough to give you a pretty good idea what's going on.
- If necessary, make an explicit call to System.gc(). Be aware that the objects
may still be in scope and consequently not eligible to be collected.
Next we move to the discussion group found at Java Gaming.
Here's an interesting result. A question was raised as to the differences
in performance between C++ and Java when calcuating Fast Fourier Transforms
(FFT). It was noted that for smallish vectors (4^6), Java is half as fast as C++.
Between the sizes of 4^6 4^7, Java catches and and is sometimes faster than C++.
Note, one should be wary of the effects of the HotSpot compiler kicking in when
performing these types of tests.
There was yet another issue with GC. A poster was commenting that GC was
causing his display to jitter. The problem was further isolated to the
Graphic.drawImage() method call. After some investigation, it was discovered
that when you call drawImage with a transform, it creates a temporary image
object. Removing the transform avoided the creation of the temporary image and
smoothed out the video.
And finally, from the Middleware company
we have a couple of intesting posts. The first one has to do with performing
a JDBC call while inside a constructor. All of the responses suggested that the
JDBC code should be removed from the constructor. One respondant suggested that
the JDBC call be contained in a factory object (Factory Pattern). As much as I
feel that factory objects are over used, this seems like a practical solution
to this problem.
There was yet another call for profiling tools. In addition to the usual suspects,
jProbe and OptimizeIt, VTune from Intel was offered as a possibility. You can
find it at www.intel.com/software/products/vtune.
In another thread one poster tested local interfaces for EJB and
found no improvement. The responders pointed out the the app server
(Weblogic) automatically uses local calls for locally reachable EJBs,
even when the EJBs are built using remote interfaces. This improves
performance, and explains the lack of improvement.
/*
* @author Kirk Pepperdine
* @since Dec 5, 2001
*/
import java.util.HashMap;
//
public class CastTest {
//
/**
* Calcuate the overhead of performing a lookup and assignment.
* This method performs every step execpt storing the objects
* as a String.
*/
public static long overhead(int iterations, HashMap map, String key) {
Object[] object = new Object[iterations];
Object[] object2 = new Object[iterations];
long startTime = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
object[i] = map.get(key);
object2[i] = object[i];
}
return System.currentTimeMillis() - startTime;
}
//
/**
* Calculate the cost of performing a cast.
*/
public static long castTime(int iterations, HashMap map, String key) {
//
Object[] object = new Object[iterations];
String[] string = new String[iterations];
long startTime = System.currentTimeMillis();
//
for (int i = 0; i < iterations; i++) {
object[i] = map.get(key);
string[i] = (String)object[i];
}
//
return System.currentTimeMillis() - startTime;
}
//
/**
* Calculate the cost of performing a toString() method call
*/
public static long toStringTime(int iterations, HashMap map, String key) {
Object[] object = new Object[iterations];
String[] string = new String[iterations];
long startTime = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
object[i] = map.get(key);
string[i] = object[i].toString();
}
return System.currentTimeMillis() - startTime;
}
//
public static void main(String[] args) {
HashMap map = new HashMap();
String s = "xxxx";
map.put(s,s);
int iterations = Integer.parseInt(args[0]);
long overHead = CastTest.overhead(iterations,map,s);
long cast = CastTest.castTime(iterations,map,s);
long toString = CastTest.toStringTime(iterations,map,s);
System.out.println("overhead is " + overHead + "ms");
System.out.println("toString() " + (toString - overHead) + "ms");
System.out.println("cast " + (cast - overHead) + "ms");
}
}
Kirk Pepperdine.
http://www.onjava.com/pub/a/onjava/2001/12/05/optimization.html
Measuring JDBC performance (Page last updated December 2001, Added 2001-12-26, Author Jack Shirazi). Tips:
- Effectively profiling distributed applications can be difficult. I/O can show up as significant in profiling, simply because of the nature of a distributed application.
- It can be unclear whether threads blocking on reads and writes are part of a significant bottleneck or simply a side issue.
- When profiling, it is usually worthwhile to have separate measurements available for the communication subsystems.
- Wrapping the JDBC classes provides an effective technique for measuring database calls.
- [Article discusses how to create JDBC wrapers to measure the performance of database calls].
- If more than a few rows of a query are being read, then the ResultSet.next() method can spend a significant amount of time fetching rows from the database, and this time should be included in measurements of database access.
- JDBC wrappers are simple and robust, and require very little alteration to the application using them (i.e, are low maintenance), so they are suitable to be retained within a deployed application.
http://www.onjava.com/pub/a/onjava/2001/12/19/oraclejdbc.html
Oracle JDBC tips (Page last updated December 2001, Added 2001-12-26, Author Donald Bales). Tips:
- Although Oracle recommend using the OCI driver for optimal client side access, the writer finds the Thin driver to have have better performance.
- Turn off autocommit, Connection.setAutoCommit(false).
- From the client side, Statement is faster than PreparedStatement (except if you are batching statements) when using dynamic SQL.
- Use PreparedStatements for all, except dynamic, SQL statements.
- Use PreparedStatements for batching repetitive inserts or updates.
- OraclePreparedStatement.setExecuteBatch() (proprietary method) is the fastest way to execute batch statements.
- Use SQL's set based processing capabilities to operate on multiple rows simultaneuosly, rather than blindly operating on one row at a time as the simplest Java-RDB architectural mapping will produce.
http://www.oreilly.com/catalog/jorajdbc/chapter/ch19.html
Chapter 19, "Performance" of Java Programming with Oracle JDBC (Page last updated December 2001, Added 2001-12-26, Author Donald Bales). Tips:
- Performance should be considered at the start of a project.
- Use the EXPLAIN PLAN facility to explain how the database's optimizer plans to execute your SQL statements, to identify performance improvements such as additional indexes.
- If more than one SQL statement is executed by your program, you can gain a small performance increase by turning off auto-commit.
- It takes about 65 iterations of a prepared statement before its total time for execution catches up with a statement, because of prepared statement initialization overheads.
- Use PreparedStatements to batch statements for optimal performance.
- The Thin driver is faster than the OCI driver. This is contrary to Oracle's recommendation.
- A SELECT statement makes two round trips to the database, the first for metadata, the second for data. Use OracleStatement.defineColumnType() to predefine the SELECT statement, thus providing the JDBC driver with the column metadata which then doesn't require the first database trip.
- Given a simple SQL statement and a stored procedure call that accomplishes the same task, the simple SQL statement will always execute faster because the stored procedure executes the same SQL statement but also has the overhead of the procedure call itself. On the other hand complex tasks requiring several SQL statements can be faster using stored procedures as fewer network trips and data transfers will be needed.
http://www.fawcette.com/javapro/2002_01/magazine/columns/weblication/
Database performance (Page last updated December 2001, Added 2001-12-26, Author Peter Varhol). Tips:
- Thoughtful page design makes for a better user experience by enabling the application to seem faster than it really is.
- Use the flush method associated with the out object to display static text and graphics on the browser page before the database query returns, to prevent the user from having to look at a blank page for a long time.
- ResultSet types affect updates. TYPE_FORWARD_ONLY: no updating allowed; TYPE_SCROLL-SENSITIVE: update immediately; TYPE_SCROLL_INSENSITIVE: update when the connection is closed. (Concurrency type must be set to CONCUR-UPDATABLE to allow the table to be updated.)
- Performance can be better if changes to the database are batched: turn off autocommit; add multiple SQL statements using the Statement.addBatch() method; execute Statement.executeBatch().
- Scaled systems need optimized SQL calls, querying the right amount of data, and displaying pages before the query is complete.
- Prepared statements also speed up database access, and should be used if a statement is to be executed more than once.
http://www-105.ibm.com/developerworks/education.nsf/java-onlinecourse-bytitle/56A6275393F0BE5786256AFD004DBBB4?OpenDocument
JDBC tutorial (requires free registration) (Page last updated November 2001, Added 2001-12-26, Author Robert J. Brunner). Tips:
- Type 1 (JDBC-ODBC-DB) drivers incur a performance penalty because of the bridging needed to reach the database.
- [Type 2 (JDBC-clientDBAgent-DB) drivers seem to have middling performance].
- Type 3 (JDBC-Middleware-DB) drivers incur a performance penalty because of the bridging needed to reach the database, but does introduce optimization potential from the location of the middleware.
- Type 4 (JDBC-DB) drivers typically provide optimum driver performance.
- The higher the level of transaction protection, the higher the performance penalty. Transaction levels in order of increasing level are: TRANSACTION_NONE, TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE. Use Connection.setTransactionIsolation() to set the desired tansaction level.
- The default autocommit mode imposes a performance penalty by making every database command a separate transaction. Turn off autocommit (Connection.setAutoCommit(false)), and explicitly specify transactions.
- Batch operations by combining them in one transaction, and in one statement using Statement.addBatch() and Statement.executeBatch().
- Savepoints (from JDBC3.0) require expensive resources. Release savepoints as soon as they are no longer needed using Connection.releaseSavepoint().
- Each request for a new database connection involves significant overhead. This can impact performance if obtaining new connections occurs frequently. Reuse connections from connection pools to limit the cost of creating connections. [The tutorial lists all the overheads involved in creating a database connection].
- The ConnectionPoolDataSource (from JDBC3.0) and PooledConnection interfaces provide built-in support for connection pools.
- Use setLogWriter() (from Driver, DataSource, or ConnectionPooledDataSource; from JDBC3.0) to help trace JDBC flow.
- Use Connection.setReadOnly(true) to optimize read-only database interactions.
- Use Connection.nativeSQL() to see how the SQL query will execute in the database to help ensure that the SQL is optimized.
http://www-105.ibm.com/developerworks/education.nsf/java-onlinecourse-bytitle/975BFD2C367CFFD686256B0500581B3B?OpenDocument
Advanced JDBC tutorial (requires free registration). (Page last updated November 2001, Added 2001-12-26, Author Robert J. Brunner). Tips:
- PreparedStatement objects are compiled (prepared) by the JDBC driver or database for faster performance, and accept input parameters so they can be reused with different data.
- Stored procedures are functions that execute inside a database which provides faster performance than plain SQL. Java supports stored procedures from CallableStatement objects.
http://developer.java.sun.com/developer/technicalArticles/J2EE/J2EEpatterns/
Performance optimizing design patterns for J2EE (Page last updated December 2001, Added 2001-12-26, Author Vijay Ramachandran). Tips:
- For read-only access to a set of data that does not change rapidly, use the Fast Lane Reader pattern which bypasses the EJBs and uses a (possibly non-transactional) data access object which encapsulates access to the data. Use the Fast Lane Reader to read data from the server and display all of them in one shot.
- When you need to access a large remote list of objects, use the Page-by-Page Iterator pattern which sends smaller subsets of the data as requested until the client no longer want any more data. Use the Page-by-Page Iterator to send lists of simple objects from EJBs to clients.
- When the client would request many small data items which would require many remote calls to satisfy, combine the multiple calls into one call which results in a single Value Object which holds all the data required to be transferred. Use the Value Object to send a single coarse-grained object from the server to the client(s).
http://www.onjava.com/pub/a/onjava/2001/12/19/eejbs.html
EJBs are wonderful (Page last updated December 2001, Added 2001-12-26, Author Tyler Jewell). Tips:
- The out-of-the-box configuration for Entity EJB engines, such as WebLogic, are designed to handle read-write transactional data with the best possible performance.
- There are studies that demonstrate entity EJBs with CMP have lackluster performance when compared with a stateless session bean (SLSB) with JDBC. [Author points out however that SLSB/JDBC combination is less robust, less configurable, and less maintainable].
- Configure separate deployments for each entity bean for different usage patterns (e.g. typical 85% read-only, 10% read-write, 5% batch update), and partition the presentation layer to use the appropriate corresponding deployment (e.g. read requests use the read-only deployment).
http://www.fawcette.com/javapro/2001_12/magazine/features/kkothapalli/
EJB performance tips (Page last updated December 2001, Added 2001-12-26, Author Krishna Kothapalli and Raghava Kothapalli). Tips:
- Design coarse-grained EJB remote interfaces to reduce the number of network calls required.
- Combine remote method calls into one call, and combine the data required for the calls into one transfer.
- Reduce the number of JNDI lookups: cache the home handles.
- Use session bean wrapper for returning multiple data rows from an entity bean, rather than returning one row at a time.
- Use session beans for database batch operations, entity beans typically operate only one row at a time.
- Use container-managed persistence (CMP) rather than bean-managed persistence (BMP).
- Use entity beans when only a few rows are required for the entity, and when rows need to be frequently updated.
- Use the lowest impact isolation (transaction) level consistent with maintaining data coherency. Highest impact down: TRANSACTION_SERIALIZABLE, TRANSACTION_REPEATABLE_READ, TRANSACTION_READ_COMMITED, TRANSACTION_READ_UNCOMMITED.
- Correctly simulate the production environment to tune the application, and use profiling and other monitroing tools to identify bottlenecks.
- Tune the underlying system, e.g. TCP/IP parameters, file limits, connection pool parameters, EJB pools sizes, thread counts, number of JVMs, JVM heap size, shared pool sizes, buffer sizes, indexes, SQL queries, keep/alive parameters, connection backlogs.
- Use clustering to meet higher loads or consider upgrading the hardware.
http://www.onjava.com/pub/a/onjava/2001/12/12/jms_not.html
JMS & CORBA (Page last updated December 2001, Added 2001-12-26, Author Steve Trythall). Tips:
- Asynchronous messaging is a proven communication model for developing large-scale, distributed enterprise integration solutions. Messaging provides more scalability because senders and receivers of messages are decoupled and are no longer required to execute in lockstep.
http://www.javaworld.com/javaworld/jw-12-2001/jw-1207-hprof.html
The hprof profiler (Page last updated December 2001, Added 2001-12-26, Author Bill Pierce). Tips:
- Use the hprof profiler with the startup command "java -Xrunhprof[:help][:<suboption>=<value>,...] MyMainClass".
- [Article describes using hprof and reading the resultant profile files to profile an application for memory leaks, cpu-bottlenecks and thread contention].
- hprof can be used to profile object allocation (heap option), method bottlnecks (cpu option) and thread contention (monitor option).
http://www.onjava.com/pub/a/onjava/excerpt/JavaRMI_10/index.html
Chapter 10, "Serialization" from "Java RMI" (Page last updated November 2001, Added 2001-12-26, Author William Grosso). Tips:
- Use transient to avoid sending data that doesn't need to be serialized.
- Serialization is a generic marshalling mechanism, and generic mechanisms tend to be slow.
- Serialization uses reflection extensively, and this also makes it slow.
- Serialization tends to generate many bytes even for small amounts of data.
- The Externalizable interface is provided to solve Serialization's performance problems.
- Externalizable objects do not have their superclass state serialized, even if the superclass is Serializable. This can be used to reduce the data written out during serialization.
- Use Serializable by default, then make classes Externalizable on a case-by-case basis to improve performance.
http://developer.java.sun.com/developer/community/chat/JavaLive/2001/jl1113.html
Sun community chat on iPlanet (Page last updated November 2001, Added 2001-12-26, Author Edward Ort). Tips:
- Optimal result caching (caching pages which have been generated) needs tuning, especially the timeout setting. Make sure the timeout is not too short.
http://www.javaworld.com/javaworld/jw-12-2001/jw-1207-java101.html
Article about garbage collection and finalization. (Page last updated December 2001, Added 2001-12-26, Author Jeff Friesen). Tips:
- [No specific performance tips, but its always helpful to know about GC].
http://www.fawcette.com/javapro/2002_01/magazine/features/rgrehan/
How to Climb a B-tree (Page last updated December 2001, Added 2001-12-26, Author Rick Grehan). Tips:
- A B-tree outperforms a binary tree when used for external sorting (for example, when the index is stored out on disk) because searching a binary tree cuts the number of keys that need searching in half for every node searched, whereas B-tree searching cuts the number of keys that have to be searched by approximately 1/n, where n is the number of keys on a node.
- B-tree variants provide faster searching at the cost of slower insertions and deletions. Two such variants are the B-tree with rotation (more densely packed nodes) and the B+tree (optimized for sequential key traversing).
- [Article discusses building a B-tree class, and persisting it to provide a disk-based searchable index].
http://developer.java.sun.com/developer/technicalArticles/releases/nio/
The java.nio packages (updated) (Page last updated December 2001, Added 2001-10-22, Author John Zukowski). Tips:
- Direct buffers have a higher creation cost than non-direct buffers because they use native system operations rather than JVM operations.
- Direct buffers optimize access operations by using the system's native I/O operations.
- Reduce threads by multiplexing I/O using selectors: The new I/O capabilities, allow you to create a Web server that does not require one thread per connection.
http://www.javaworld.com/javaworld/jw-12-2001/jw-1214-jylog.html
JyLog logger (Page last updated December 2001, Added 2001-12-26, Author Sanjay Dahiya). Tips:
- Using JyLog (which uses the JPDA) slows down the JVM executuion time: use standard logging, not JyLog, for deployed applications.
http://www.devx.com/premier/mgznarch/javapro/2001/01dec01/sl0112/sl0112-1.asp
Creating Web-based, interactive graphics. (Page last updated December 2001, Added 2001-12-26, Author Steve Lloyd). Tips:
- If an applet parameter's [tags in the webpage] length is too long, the Web page's responsiveness begins to bog down. Move all but the essential parameters from the APPLET tag to a dedicated HTTP link between the applet and the servlet. This allows page loading and applet initialization to occur at the same time over separate connections.
- Close java.sql.Statements when finished with.
http://www.javaworld.com/javaworld/javaqa/2001-12/01-qa-1207-ziprmi.html
Data compression (Page last updated December 2001, Added 2001-12-26, Author Tony Sintes). Tips:
- [Article covers how to add zip compression to RMI communications].
http://www.precisejava.com/javaperf/j2ee/EJB.htm
EJB performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- EJB calls are expensive. A method call from the client could cover all the following: get Home reference from the NamingService (one network round trip); get EJB reference (one or two network roundtrips plus remote creation and initialization of Home and EJB objects); call method and return value on EJB object (two or more network rountrips: client-server and [mutliple] server-db; several costly services used such as transactions, persistence, security, etc; multiple serializations and deserializations).
- If you don't need EJB services for an object, use a plain Java object and not an EJB object.
- Use Local interfaces (from EJB2.0) if you deploy both EJB Client and EJB in the same JVM. (For EJB1.1 based applications, some vendors provide pass-by-reference EJB implementations that work like Local interfaces).
- Wrap multiple entity beans in a session bean to change multiple EJB remote calls into one session bean remote call and several local calls (pattern called SessionFacade).
- Change multiple remote method calls into one remote method call with all the data combined into a parameter object.
- Control serialization by modifying unnecessary data variables with 'transient' key word to avoid unnecessary data transfer over network.
- Cache EJBHome references to avoid JNDI lookup overhead (pattern called ServiceLocator).
- Declare non-transactional methods of session beans with 'NotSupported' or 'Never' transaction attributes (in the ejb-jar.xml deployment descriptor file).
- Transactions should span the minimum time possible as transactions lock database rows.
- Set the transaction time-out (in the ejb-jar.xml deployment descriptor file).
- Use clustering for scalability.
- Tune the EJB Server thread count.
- Use the HttpSession object rather than a Stateful session bean to maintain client state.
- Use the ECperf benchmark to help differentiate EJB server performances.
- Tune the Stateless session beans pool size to minimize the creation and destruction of beans.
- Use the setSessionContext() or ejbCreate() method to cache bean specific resources. Release acquired resources in the ejbRemove() method.
- Tune the Stateful session beans cache size to and time-out minimize activations and passivations.
- Allow stateful session beans to be removed from the container cache by explicitly using the remove() method in the client.
- Tune the entity beans pool size to minimize the creation and destruction of beans.
- Tune the entity beans cache size to minimize the activation and passivation of beans (and associated database calls).
- Use the setEntityContext() method to cache bean specific resources and release them from the unSetEntityContext() method.
- Use Lazy loading to avoid unnecessary pre-loading of child data.
- Choose the lowest cost transaction isolation level that avoids corrupting the data. Transaction levels in increasing cost are: TRANSACTION_READ_UNCOMMITED, TRANSACTION_READ_COMMITED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE.
- Use the lowest cost locking available from the database that is consistent with any transaction.
- Create read-only entity beans for read only operations.
- Use a dirty flag where supported by the EJB server to avoid writing unchanged EJBs to the database.
- Commit the data after the transaction completes rather than after each method call (where supported by EJB server).
- Do bulk updates to reduce database calls.
- Use CMP rather than BMP to utilize built-in performance optimization facilities of CMP.
- Use ejbHome() methods for global operations (from EJB2.0).
- Tune the connection pool size to minimize the creation and destruction of database connections.
- Use JDBC directly rather than using entity beans when dealing with large amounts of data such as searching a large database.
- Combine business logic with the entity bean that holds the data needed for that logic to process.
- Tune the Message driven beans pool size to optimize the concurrent processing of messages.
- Use the setMesssageDrivenContext() or ejbCreate() method to cache bean specific resources, and release those resources from the ejbRemove() method.
http://www.precisejava.com/javaperf/j2ee/JDBC.htm
JDBC performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- Use the fastest driver available to the database: normally type 4 (preferably) or type 3.
- Tune the defaultPrefetch and defaultBatchValue settings.
- Get database connections from a connection pool: use javax.sql.DataSource for optimal configurability. Use the vendor's connection pool; or ConnectionPoolDataSource and PooledConnection from JDBC2.0; or a proprietary connection pool.
- Batch your transactions. Turn off autocommit and explicitly commit a set of statements.
- Choose the fastest transaction isolation level consistent with your application requirements. Levels from slowest to fastest are: TRANSACTION_NONE, TRANSACTION_READ_UNCOMMITED, TRANSACTION_READ_COMMITED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE.
- Close resources (e.g. connections) when finished with them.
- Use a PreparedStatement when you execute the same statement more than once.
- Use CallableStatement to execute stored procedures. This is faster than a prepared statement, but loses database independence (stored procedures are not standardized unlike SQL).
- Batch updates and accesses with Statements and ResultSets (with executeBatch() and setFetchSize()).
- Set up the proper direction for processing rows.
- Use the proper getXXX() methods.
- Write SQL queries that minimize the data returned.
- Cache read-only and read-mostly tables data.
- Use the Page-by-Page Iterator pattern to repeatedly pass small amounts of data rather than huge chunks.
http://www.precisejava.com/javaperf/j2ee/Servlets.htm
Servlet performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- Use the servlet init() method to cache static data, and release them in the destroy() method.
- Use StringBuffer rather than using + operator when you concatenate multiple strings.
- Use the print() method rather than the println() method.
- Use a ServletOutputStream rather than a PrintWriter to send binary data.
- Initialize the PrintWriter with the optimal size for pages you write.
- Flush the data in sections so that the user can see partial pages more quickly.
- Minimize the synchronized block in the service method.
- Implement the getLastModified() method to use the browser cache and the server cache.
- Use the application server's caching facility.
- Session mechanisms from fastest to slowest are: HttpSession, Hidden fields, Cookies, URL rewriting, the persistency mechanism.
- Remove HttpSession objects explicitly in your program whenever you finish the session.
- Set the session time-out value as low as possible.
- Use transient variables to reduce serialization overheads.
- Disable the servlet auto reloading feature.
- Tune the thread pool size.
http://www.precisejava.com/javaperf/j2ee/JSP.htm
JSP performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- Use the jspInit() method to cache static data, and release them in the jspDestroy() method.
- Use the jspInit() method to cache static data.
- Use StringBuffer rather than using + operator when you concatenate multiple strings.
- Use the print() method rather than the println() method.
- Use a ServletOutputStream rather than a PrintWriter to send binary data.
- Initialize the PrintWriter with the optimal size for pages you write.
- Flush the data in sections so that the user can see partial pages more quickly.
- Minimize the synchronized block in the service method.
- Avoid creating a session object with the directive <%@ page session="false" %>
- Increase the buffer size of System.out with the directive <%@ page buffer="12kb" %>
- Use the include directive instead of the include action when you want to include another page.
- Minimize the scope of the 'useBean' action.
- Custom tags incur a performance overhead. Use as few as possible.
- Use the application server's caching facility, and the session and application objects (using getAttribute()/setAttribute()). There are also third-party caching tags available.
- Session mechanisms from fastest to slowest are: session, Hidden fields, Cookies, URL rewriting, the persistency mechanism.
- Remove 'session' objects explicitly in your program whenever you finish the session.
- Reduce the session time-out as low as possible.
- Use 'transient' variables to reduce serialization overheads.
- Disable the JSP auto reloading feature.
- Tune the thread pool size.
http://www.precisejava.com/javaperf/j2ee/JMS.htm
JMS performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- Start the consumer before you start the producer so that the initial messages do not need to queue.
- Use a ConnectionConsumer to process messages concurrently with a ServerSessionPool.
- Close resources (e.g. connections, session objects, producers, consumers) when finished with them.
- DUPS_OK_ACKNOWLEDGE and AUTO_ACKNOWLEDGE perform better than CLIENT_ACKNOWLEDGE.
- Use separate transactional sessions and non-transactional sessions for transactional and non-transactional messages.
- Tune the Destination parameters: a smaller capacity increases message throughput; a higher redelivery delay and lower redelivery limit reduces the overhead.
- Choose non-durable (NON_PERSISTENT) messages wherever appropriate to avoid the persistency overhead.
- Set the TimeToLive value as low as feasible (default is for messages to never expire).
- Receive messages asynchronously with a MessageListener implementation.
- Choose the message type that minimizes memory overheads.
- Use 'transient' variables to reduce serialization overheads.
http://www.precisejava.com/javaperf/j2ee/Patterns.htm
Pattern performance tips (Page last updated November 2001, Added 2001-12-26, Authors Ravi Kalidindi and Rohini Datla). Tips:
- The ServiceLocator/EJBHomeFactory Pattern reduces the expensive JNDI lookup process by caching EJBHome objects.
- The SessionFacade Pattern reduces network calls by combining accesses to multiple Entity beans into one access to the facade object.
- The MessageFacade/ServiceActivator Pattern moves method calls into a separate object which can execute asynchronously.
- The ValueObject Pattern combines remote data into one serializable object, thus reducing the number of network transfers required to access multiple items of remote data.
- The ValueObjectFactory/ValueObjectAssembler Pattern combines remote data from multiple remote objects into one serializable object, thus reducing the number of network transfers required to access multiple items of remote data.
- The ValueListHandler Pattern: avoids using multiple Entity beans to access the database, using Data Access Objects which explicitly query the database; and returns the data to the client in batches (which can be terminated) rather than in one big chunk, according to the Page-by-Page Iterator pattern.
- The CompositeEntity Pattern reduces the number of actual entity beans by wrapping multiple java objects (which could otherwise be Entity beans) into one Entity bean.
http://java.sun.com/docs/books/performance/1st_edition/html/JPIOPerformance.fm.html
Chapter 4, "I/O Performance" of "Java Platform Performance: Strategies and Tactics." (Page last updated 2000, Added 2001-12-27, Author Steve Wilson and Jeff Kesselman). Tips:
- Buffer i/o operations.
- Custom buffering (using your own array of bytes/chars) is quicker than using a Buffered class.
- Application specific i/o can be tuned, e.g. caching in memory frequently served pages of a HTTP server.
- Deafault Serialization is slow.
- Use the
transient
keyword to define fields to avoid having those fields serialized. Examine serialized objects to determine which fields do not need to be serialized for the application to work.
http://java.sun.com/docs/books/performance/1st_edition/html/JPRAMFootprint.fm.html
Chapter 5, "RAM Footprint" of "Java Platform Performance: Strategies and Tactics." (Page last updated 2000, Added 2001-12-27, Author Steve Wilson and Jeff Kesselman). Tips:
- Virtual memory is many times slower than RAM: try to fit the application into available RAM on the target platform.
- Runtime.totalMemory() and Runtime.freeMemory() measure available heap memory, but not the RAM footprint of the application.
- Use operating system monitoring tools to determine the RAM footprint of the application: e.g. task manager on Windows NT, pmap -x and ps on Solaris.
- Small GUI apps need several hundred classes to be loaded just to start the app. Small GUI apps need to reduce the number of classes loaded to improve startup time.
- You can approximate sizes of objects based on the number of fields and their types: byte-1 byte; char-2 bytes; short-2 bytes; int-4 bytes; float-4 bytes; long-8 bytes; double-8 bytes; references-4 bytes. JVMs will impose additional overheads.
- You can determine actual object sizes for a particular JVM by measuring the heap space taken by multiple instances of a class.
- Use profiling to determine the overal size cost of a class of objects, to determine whether it is worth reducing the size cost of the class.
- Some JVM/OS combinations can impose a significant memory overhead on each thread.
- Use 'java -verbose <MyMainClass>' to identify all classes that are loaded.
http://java.sun.com/docs/books/performance/1st_edition/html/JPClassLoading.fm.html
Chapter 6, "Controlling Class Loading" of "Java Platform Performance: Strategies and Tactics." (Page last updated 2000, Added 2001-12-27, Author Steve Wilson and Jeff Kesselman). Tips:
- To avoid loading unnecessary classes (e.g. when the JIT compiles methods which refer to unused classes), use Class.forName() instead of directly naming the class in source. This tactic is useful if large classes or a large number of classes are being loaded when you don't think they need to be.
- Combine listener functionality into one class to avoid an explosion of generated inner classes. This technique increases maintenance costs.
- Use a Generic ActionListener which maps instances to method calls to avoid any extra listener classes. This has the drawback of losing compile-time checks. java.lang.reflect.Proxy objects can be used to generalize this technique to multiple interfaces.
- Run multiple applications in the same JVM. [Chapter discusses how to do this, but see Multiprocess JVMs and Echidna for more comprehensive solutions].
Jack Shirazi
Last Updated: 2024-08-26
Copyright © 2000-2024 Fasterj.com. All Rights Reserved.
All trademarks and registered trademarks appearing on JavaPerformanceTuning.com are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries. JavaPerformanceTuning.com is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
URL: http://www.JavaPerformanceTuning.com/newsletter013.shtml
RSS Feed: http://www.JavaPerformanceTuning.com/newsletters.rss
Trouble with this page? Please contact us