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 ...
Tips October 2007
Get rid of your performance problems and memory leaks!
Get rid of your performance problems and memory leaks!
Back to newsletter 083 contents
How to Handle Java Finalization's Memory-Retention Issues (Page last updated September 2007, Added 2007-10-30, Author Tony Printezis, Publisher Sun). Tips:
- Finalization allows you to perform postmortem cleanup on objects that the garbage collector has found to be unreachable, by implementing the protected void finalize() method.
- Sometime after an instance has become unreachable, the JVM will call its finalize() method.
- A finalize method can make the object reachable again by, say, making it reachable from a static field, for example. This programming practice is not recommended, but unfortunately the Java programming language allows it.
- The lifecycle sequence of an object is: created; unreachable; GCed - reclaimed if no finalize(), otherwise added to finalization queue; finalized; GCed and reclaimed.
- Because a finalizable object has an extra step during it's first GC, and then another GC too, it slows down the reclamation process.
- A finalizable object has an extra step during creation of the object as the JVM then records that it is finalizable.
- The garbage collector needs a minimum of two cycles to reclaim a finalizable object and needs to retain all other objects reachable from that object during this process.
- Classes which inherit finalize() methods will also go through at least two GC ccles before being reclaimed, meaning that any reources they reference will stay alive longer than normal.
- Favor composition over inheritance to reduce unintentional inherited dependencies.
- Explicit nulling of fields is rarely good practice, but doing so for instance fields in a finalize() method is one of the rare occasions when it is justified.
- Instances of inner classes have an implicit reference to the instance of the outer class that created them. Therefore, if an inner class instance is queued up for finalization, it would also have retained the corresponding outer class instance, keeping that instance alive for longer than it needs to be.
- You can replace a finalize() method by holding a weak reference to an object and explicit calling an equivalent method that frees up resources when the weak reference is nulled and enqueued.
- You should also use finalization only when it is absolutely necessary. Finalization is a nondeterministic -- and sometimes unpredictable -- process
Finalization, Threads and the Java Technology-Based Memory Model (Page last updated June 2005, Added 2007-10-30, Author Hans-J. Boehm, Publisher ). Tips:
- Finalizers are unordered and can be executed concurrently with any other threads.
- There is no guarantee at all about when a finalize() method will be called - it may never be called.
- Avoid having a finalize() method if at all possible (much better for performance)
- Even if a program is single-threaded, finalizers run in a separate thread - so a single-threaded Java program still needs synchronization!
- The finalize() method can run earlier than you expect if the compiler anticipates that a reference goes out of scope earlier than you think.
- Because finalization is unordered, you can potentially have resources freed in any order, even if they are dependent on each other - which is very dangerous if you are not prepared for that.
- If you need to finalize things, you should be synchronizing any access that can occur for those objects.
Why WeakHashMap Sucks (Page last updated August 2007, Added 2007-10-30, Author Cliff Click Jr., Publisher AzulSystems). Tips:
- A failed "equals" calls in a WeakHashMap takes time, and will typically cause a ConcurrentGC to believe the Key should be kept alive for another cycle. Indefintely (or until a pause happens).
- You should use Soft References for caching.
Did You Know ... (Page last updated October 2007, Added 2007-10-30, Author Jon Masamitsu, Publisher Sun). Tips:
- The low-pause collector (UseConcMarkSweepGC) will use (ParallelGCThreads + 3)/4) threads during the concurrent mark phase in Java 6 if CMSConcurrentMTEnabled is true (this was introduced as the mark phase was found to be overwhelmed by generated garbage at about 8 CPUs, so this introduces extra threads at a rate that should cope with extra CPUs).
- CMSMaxAbortablePrecleanTime (default value 5 seconds) is the time the low-pause collector (UseConcMarkSweepGC) waits doing sampling of the young generation to chunk it up for the parallel re-mark phase. Ideally this wait should include a minor GC. It maye be worth tuning the value of this option to get a minor GC during this wait to minimize the pause time in the stop-the-world re-mark phase that follows the wait. But waiting too long could give the re-mark yet more work to do, so lengthing the pause. Finally, setting CMSScavengeBeforeRemark to true will force a minor collection to occur just before the re-mark - which may be better (makes the re-mark more parallel so shorter) or worse (if the minor GC itself is long enough, it looks like one long pause).
- Huge methods (8000 bytes of bytecode) are not JIT compiled with HotSpot.
- You should factor huge methods to be several smaller ones.
- Un-JITed methods have to have OOP maps generated by the GC - this slows down the GC, and can be particularly slow for large methods.
- If you have some huge methods (>8000 bytes of bytecode) and GC's are taking a very long time, you could try -XX:-DontCompileHugeMethods which will tell the JIT to ignore its size limit on compilation and compile any size method (this is not generally recommended). Note that JSPs can easily produce methods with a size of over 8000 bytes of bytecode, and it may be worth factoring JSPs to smaller aggregates of pages.
The Law of the Overstocked Haberdashery (Page last updated August 2007, Added 2007-10-30, Author Heinz M. Kabutz, Publisher javaspecialists). Tips:
- Having too many threads is bad for your application. Performance will degrade and debugging will become difficult.
- You can reduce the stack size with the -Xss<size_of_stack> JVM parameter, e.g. -Xss48k
- Use thread pools to avoid having too many threads in your application (e.g. using Executors.newFixedThreadPool(12)).
- If you do use thread pools, make sure that you make the number of threads configurable.
Concurrency Testing Java Apps (Page last updated October 2007, Added 2007-10-30, Author Frank Cohen, Publisher TheServerSide). Tips:
- A test automation tool needs to support: Unit test of specific functions; Varying the input data; Sequences of functional tests; Concurrently running client threads; Multiple test machines (clients and servers); Variations in the mix of concurrent running threads; Varying the test parameters.
- You can never create a deterministic test to uncover a non-deterministic concurrency issue. You need to test concurrently and vary sufficiently to (luckily) uncover race conditions.
- Observe at least the following metrics: the JVM (heap, memory, thread, object instantiations, and garbage collection); Service calls (time to serve request, external service and database query times, properties settings, and service interface request values and schema); Subsystems (e,g, database transaction logs, input parameters, and query operations).
- Use a monitoring tools like Glassbox which watches an application server receive requests, operate objects and EJBs, communicate with databases, and interact with message buses. Such tools provide a service interface that test environments can use to automate the correlations.
- Correlation analysis helps to associate issues, but a more complex tool (like Glassbox) is needed to trace causality through the system.
- A correlation analysis might reveal that a slow operation occurred at the same time the database was running slowly overall, suggesting a database tuning problem. A more comples virtual application model allows walking the usage relationships in both directions, revealing that the slow database was in fact caused by a long-running report query and identifies that as the cause.
Back to newsletter 083 contents
Last Updated: 2021-06-29
Copyright © 2000-2021 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.
RSS Feed: http://www.JavaPerformanceTuning.com/newsletters.rss
Trouble with this page? Please contact us