Skip to main content

Some J2EE Performance Tips

Posted by caroljmcdonald on March 9, 2004 at 10:00 AM PST

You need to plan for performance and scalability
through out
your application development process from architecture to
implementation to
testing. Like security this is not something that can easily be stuck
on at the
last minute. During design, coding and testing you need to pay
attention to resource
consumption
:

  • CPU: watch for inefficient code
    especially for algorithms and loops Avoid excessive parsing and type
    conversions.
  • Memory: If you use too much
    memory it can affect performance by causing longer and frequent garbage
    collection. Make sure that any unused objects are no longer referenced
    so that the garbage collector can reclaim them. For an explanation of
    Memory Leaks in Java Programs see href="http://www.adtmag.com/java/articleold.asp?id=165">Memory Leaks in Java Programs
    . Take advantage of J2EE Application server caching and object pools
    (see tuning caching and pooling below). Garbage collection
    tuning can have a significantly affect on performance for more
    information see: href="http://developers.sun.com/techtopics/mobility/midp/articles/garbagecollection2/">
    Improving Java Application Performance and Scalability by Reducing Garbage Collection Times
    and href="http://developers.sun.com/events/techdays/presentations/london/HotSpotPerformanceTuning.pdf">
    Sun Tech Days presentation on How to Tune the HotSpot Virtual Machine
  • Network: watch out for network
    traffic. Design coarse-grained services with Session or MDB Facades and
    always use local interfaces for other EJBs (see the Session Facade and
    DTO design patterns below).
  • Database: use connection
    pooling and statement caching. Make sure your queries are efficient.
    See JDBC tips below.

The following J2EE design patterns can
improve
performance:

  • Data Transfer Object to
    encapsulate and pass a business object’s data attributes to the
    presentation tier. Reduces remote network traffic and helps to keep a
    clean separation between JSPs and EJBs.
  • Service Locator to cache
    results of JNDI lookups
  • Value List Handler for
    querying, filtering, large amounts of data
  • Data Access Object to
    provide a simplified interface for performing complex JDBC operations
    and to encapsulate data-access logic. Allows decoupling of data-access
    optimizations
  • Session Facade:
    • To group calls to EJBs in a Coarse
      Grained Interface: to execute complex use cases in a single network
      call.
    • Use local interfaces for entity
      beans and any session EJBs that will be collocated within the
      same VM. If EJBs need to be called remotely wrap them with the session
      facade design pattern to combine methods in order to reduce remote
      invocations.
    • To group related entity or DB
      updates into 1 container managed transaction

For more on J2EE Patterns see href="http://www.corej2eepatterns.com/">Core J2EE Patterns
and J2EE Blueprints

Servlet tips: Don't store a lot of data in the HTTP Session because memory
consumption affects performance and scalability. Remove servlet sessions when they are no longer needed: call
session.invalidate()

Session EJB tips: Again because memory consumption affects performance and scalability remove stateful session beans when they are
no longer needed (for example when a user logs out) by calling
Bean.remove(). Limit the size of objects stored in session beans
due to memory cost and performance cost for  I/O  activation and
passivation. For high scalability try to use Stateless session
EJBs. You
can sometimes convert Stateful EJBs to Stateless by adding parameters
containing state information to the Stateless bean methods.

Entity Container Managed Persistence: Use CMP Entity Beans for
Object
oriented transactional persistence. Tuned CMP entity beans can usually
offer
better performance then BMP entity beans (for large queries, tabular
type
access for browsing data use the DAO pattern) With EJB 2.0 CMP
optimization is
possible because persistent fields are only accessible via get and set
methods.
Containers can optimize based on whether or not a field has been
modified, the
entity is in a transaction, relation, cache.. CMP optimizations
include:

  • Lazy Loading: Deferring loading of any
    data until it is accessed
  • Dirty Writes:Only updating data which
    has been changed in the database

For more information on CMP performance see:

Why choose CMP?


Consistency Levels in CMP:
Consistency levels are tunable in the
EJB
container, which can improve performance depending on the application.
There
are two general approaches to ensure consistency. The first is
pessimistic locking,
which serializes access to an Entity EJB during a transaction and may
lead to
decreased concurrency. The second approach is optimistic locking, and
may
result in a larger number of database round trips since it requires a
caller to
re-try if a consistency check fails at store. Optimistic locking gives
better
performance when entity contention is not high.


Database Isolation Modes
a lower database transaction isolation
levels
reduces work in the database tier, and can lead to better application
performance. Choose the lowest cost database transaction isolation
level that
avoids corrupting the application data. Use a READ_COMMITTED isolation
level
with optimistic locking if there is a low likelihood of concurrent
transactions
updating the same rows. Updates will only fail if there has been a
collision.


Getting the most out of your Application Server:

You need to set a sufficient size for the JVM's heap, Data Base
connection
pools, and EJB pools and caches. Failure to provide enough resources
results in
contention and degrades application performance. However too high
resource
settings can degrade performance as well by using too much memory,
which will
cause more frequent and longer full Garbage Collection cycles.

Tuning the caching and pooling of EJBs and JDBC can have a
significant
affect on performance.

Stateless Session beans, Message Driven Beans and
Entity
beans are pooled to improve server performance. Pooled
EJB
instances are all equivalent and indistinguishable from other pooled
instances
of the same class type. Pooling beans reduces the overhead associated
with
creating and initializing bean instances. You want to monitor and tune
the pool
to avoid excessive creation or deletion of instances, but also avoid accumulating unused instances.
Increase the bean’s
pool size
when observing excessive creation and deletion of bean instances.
Decrease the bean’s pool size when accumulating a large number of
instances in the pool, as this will cause more frequent and longer full
Garbage
Collection cycles.

For example the Sun Java Application Server has the following EJB
Container
PoolTunables:

  • steady-pool-size (not for message-driven)
  • max-pool-size (0 = unbounded)
  • pool-idle-timeout-in-seconds
  • (0 = indefinitely)

These can be set per bean type and/or as global defaults.

Stateful Session beans and Entity beans are cached
to
improve performance. Cached Stateful Session EJBs are associated with a
specific user's conversational state. Cached Entity EJBs are associated
with a
specific primary key. Caching beans gives better performance by
reducing
activations and passivations, especially since the data associated with
an instance
must be re-loaded for activation. You want to monitor and tune the
cache to
minimize the number of activations and passivations, but avoid the
accumulation
of unused instances in the cache. For Entity beans increase the
cache
size for beans with concurrent or iterative access patterns. For
Stateful session beans set the cache size to the maximum
estimated  ~
number of concurrent users. In general Increase the cache until a
good
cache hit rate is reached.

Entity Bean Commit options and the cache.
In the EJB spec there are 3 commit options for entity beans:

  • Commit Option A: At the end of the
    transaction, the instance stays in the ready state (cached) and the
    instance state is valid (ejbLoad not called)
  • Commit Option B: At the end of the
    transaction, the instance stays in the ready state (cached) but the
    instance state is NOT valid (ejbLoad will be called)
  • Commit Option C: At the end of the
    transaction, neither the instance nor its state is valid (instance will
    be passivated and returned to the pool)

Comit option B performs the best if the Entity
bean will be
accessed again. If the Entity bean is rarely reused then commit
option C
is better.  Do profiling with your application on your
application server
to determine what works best.

For example the Sun Java Application Server has the following EJB
Container
Cache Tunables:

  • commit-option (B|C) (entity beans)
  • Max-cache-size (0 = unbounded)
  • cache-idle-timeout-in-seconds
  • (0 = indefinitely)

These can be set per bean type and/or as global
defaults.

For more on tuning the EJB pool and cache see:
Performance Tuning the EJB Container

JDBC tips:

  • Test and Select a good JDBC driver for
    your application
  • Tune the connection pool size
  • Obtain a connection as close to the
    resource operation as possible and close as soon as completed in order
    to return the connection to the pool
    • Close JDBC connections in the
      finally block 
  • Index the columns in your WHERE clauses
  • Find out what is happening with your
    SQL code: use your database engine's command-line utility and run
    the SQL through the EXPLAIN SELECT command (or whatever your vendor
    provides to analyze queries)
    • Is the query utilizing indexes fully?
    • Avoid n-way joins 
    • Avoid bringing back thousands of
      rows of data
  • Turn off Auto-Commit, Group updates
    into a transaction and/or batch updates
  • To improve performance of database
    queries, use PreparedStatements and JDBC statement caching, this saves
    on SQL parsing

For example with the Sun Java Application Server you can tune JDBC
statement caching as follows:
<jdbc-connection-pool datasource-classname=
"oracle.jdbc.pool.OracleDataSource" ...>
  <property name="ImplicitCachingEnabled" 
value="true"/>
  <property name="MaxStatements" value="200"/>
</jdbc-connection-pool>

For more information on JDBC performance see
Sun Java Application Server JDBC connection pool tuning
Top Ten Oracle JDBC Tips
Oracle Best Practices in Performance and Scalability

JMS tips:
Use JMS for

  • Asynchronous Concurrent processing
  • Batch processing
  • Scalability
  • Broadcasting messages to multiple
    recipients
  • Reliable messaging 
  • Loose Coupling

XML and
Messaging:

Use XML mainly for messages between systems, inside your Application
don’t
overuse XML because parsing and processing  can cause a
performance hit.
for more JMS tips see:
Best practices to improve performance in JMS

references and more J2EE performance information:

Core J2EE Patterns
J2EE Blueprints
Java Performance
Sun Java Application Server Performance Tuning Guide
Sun Tech Days Presentation on J2EE Best Practices and Patterns
Java Performance Tuning
Bitter EJB Book
PreciseJava website

The Middleware Company J2EE Performance Case Study

J2EE Performance
J2EE Design Strategies That Boost Performance
J2EE Performance Tuning

Enterprise Java Best Practices

Related Topics >>