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: Threading Essentials course
Tips November 2007
Get rid of your performance problems and memory leaks!
Get rid of your performance problems and memory leaks!
Back to newsletter 084 contents
The Secret Life Of The Finalizer (Page last updated November 2007, Added 2007-11-28, Author Jack Shirazi, Publisher Fasterj.com). Tips:
- When a finalizable object is created, a Finalizer object pointing to it is created at the same time.
- A finalizable object is not cleared from memory in the first GC that it is no longer referenced from the application. Instead it is kept alive for the finalize() method to be called after that GC is finished.
- The "Finalizer" daemon thread is a thread that runs concurrently with the application, and it executes the finalize() method on any finalizable objects that a GC has identified would be otherwise reclaimable.
- The "Finalizer" daemon thread runs at a lower priority than the default thread priority. That means that finalizable objects will compete at a disadvantage with other application threads to get CPU time to execute finalize() methods.
- If finalizable objects are dereferenced at a fast enough rate, it is possible for the finalization queue to grow large enough to take significant amounts of memory - even enough to cause an OutOfMemoryError.
- If the finalize queue is continually growing larger in your application, you can increase the priority of the "Finalizer" daemon thread by running through all the threads to find it by name, then increase it's priority.
- For tighter control over your finalization process, you can remove the finalize() method and using your own explicit queue, your own Reference objects, and your own finalization processing thread in a very similar way that the Finalizer class processes the objects and their finalize() methods.
- The overheads of having finalizable objects are significant - try to keep the number of finalizable objects to a minimum. A few finalizable objects normally don't matter; too many can seriously stress the GC.
Monitor and diagnose performance in Java SE 6 (Page last updated September 2007, Added 2007-11-28, Author Cathy Kegley, Greg Roberts, Publisher IBM). Tips:
- From Java 5 the JVM has included a built-in MBean server called the platform MBean server, for monitoring the JVM. The Nine platform MBeans are: ClassLoadingMXBean (Class loader); CompilationMXBean (Compiler); MemoryMXBean (Memory); ThreadMXBean (Threads); RuntimeMXBean (Runtime); OperatingSystemMXBean (Operating system); GarbageCollectorMXBean (Garbage collector); MemoryManagerMXBean (Memory manager); MemoryPoolMXBean (Memory pool);
- You can monitor and manage the JVM resources through platform MBeans: directly via the MXBean interface (e.g. ManagementFactory.getRuntimeMXBean().getVmVendor()); or indirectly via the MBeanServer interface (e.g. JMXConnectorFactory.connect(new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://<addr>")).getMBeanServerConnection().getAttribute(new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME), "VmVendor");).
- Java 6 adds support for java.util.concurrent.locks in the java.lang.management package. This includes new classes that provide information about locks, as well as enhancements to the ThreadInfo, ThreadMXBean, and OperatingSystemMXBean interfaces: LockInfo contains information about a lock; and MonitorInfo extends LockInfo and contains information about an object-monitor lock.
- In Java 5, the ThreadMXBean.getThreadInfo methods report only an object monitor that a thread is waiting to acquire or is blocked from entering. In Java 6, these methods are enhanced to report the AbstractOwnableSynchronizer that a thread is waiting to acquire.
- In Java 6 the OperatingSystemMXBean interface was updated to include the getSystemLoadAverage() method, which returns the system load average for the past minute.
- Java 6 applications no longer need the -Dcom.sun.management.jmxremote option for Jconsole to see the MBeans.
- [Article shows JConsole in action, explaining the six tabs it presents: Overview, Memory, Threads, Classes, VM Summary, MBeans].
- In Java 6, JConsole includes support for the HotSpot Diagnostic MBean. This MBean was introduced in Java 6 to allow you to perform on-the-spot diagnostic operations. Its API lets users perform a heap dump and set other VM options during run time.
- From Java 6, JConsole supports plug-ins, and has a -pluginpath option. JConsole comes with a demo plug-in called JTop which shows the CPU usage of the threads running within the current application.
- Java 6 includes three command-line utilities that are useful for monitoring JVM performance statistics: jps (JVM process status tool); jstat (JVM statistics monitoring tool); jstatd (JVM jstat daemon).
- Java 6 includes a number of troubleshooting tools that can help you pinpoint portions of your application that are behaving unexpectedly: jinfo (Configuration information); jhat (Heap dump browser); jmap (Memory map); jsadebugd (Serviceability agent debug daemon); jstack (Stack trace).
Better monitors for Java (Page last updated October 2007, Added 2007-11-28, Author Theodore S. Norvell, Publisher JavaWorld). Tips:
- Hoare-style monitors makes a thread wait until some specific assertion about the monitor's state is true and can be guaranteed that it is still true after the thread has been awakened. In Hoare's version of a monitor, occupancy of the monitor is transferred directly from a signaling to a signaled thread: the state of the monitor object cannot change between the signaling thread leaving and the signaled thread arriving.
- [Article includes a details and examples of using a particlar Java implementation of Hoare-style monitors].
- To be on the safe side, fields which are used multi-threaded should be marked either as final (telling the compiler the field will not change) or volatile (so that the compiler will not assume that only one thread may access these fields).
- In Java, every object is associated with two queues: an entry queue and a wait queue. When a thread calls a method marked as synchronized, the thread will wait on the entry queue until no other thread occupies the object. On returning from a synchronized method the thread relinquishes occupancy. Threads unconditionally wait on the wait queue by calling the wait() method of the synchronizing object. A call to notify() does not relinquish exclusive access; rather it simply moves some waiting thread, if there is one, from the object's wait queue to the object's entry queue. There also is a notifyAll() method that moves all threads from the wait queue to the entry queue.
- This implementation of Hoare-style monitors supports: assertions and conditions; multiple wait queues for a thread in a wait state; tighter control over passing the mointor across threads.
Finding Memory Leaks with SAP Memory Analyzer (Page last updated July 2007, Added 2007-11-28, Author Krum Tsvetkov, Publisher SAP). Tips:
- The common approach to finding a memory leak requires more than one snapshot - you find the differences and that shows up the memory leak. But you can find memory leaks using just one heap snapshot - as long as the memory leak is sufficiently large.
- Configure the JVM to produce a heap dump when an OutOfMemoryError occurs with the -XX:+HeapDumpOnOutOfMemoryError
- In order to identify a memory leak from the single heap dump that you can get when the JVM hits an OutOfMemoryError, you need to have the heap configured large enough that a signifcant proportion of it gets filled from the memory leak.
- A technique to identify the cause of a memory leak from a single snapshot where a single large collection is causing the leak is: Look at the root objects that are retaining the most amount of memory from the object graph it holds on to (e.g. from SAP Memory Analyzer's Dominator tree view); track down through the references from the roots focusing on the objects that retain the most amount of memory from the object graph they hold on to until you reach a sudden drop in retained memory - the parent object here is the object that is likely to be directly responsible for the leak; find the variables holding on to the leak object, right up to the root to see what is ultimately causing the leak (e.g. in SAP Memory Analyzer's Dominator tree view, select the object, right-click and select "Open in Paths from GC roots...->without weak and soft references).
- A technique to identify the cause of a memory leak from a single snapshot where a single class is causing the leak is: Look at the root objects that are retaining the most amount of memory from the object graph it holds on to (e.g. from SAP Memory Analyzer's Dominator tree view); switch to the "Group by class" view to see which class holds the most amount of retained memory in the heap; find the variables holding on to the leak objects, right up to the root to see what is ultimately causing the leak (e.g. in SAP Memory Analyzer's Dominator tree view, select the object, right-click and select "Open in Paths from GC roots...->without weak and soft references).
A Shortcut to finding Performance Bottlenecks (Page last updated September 2007, Added 2007-11-28, Author Kirk Pepperdine, Publisher InfoQ). Tips:
- Performance bottlenecks are sensitive to the load that is put on the system. A different load or different pattern of load can eliminate some bottlenecks - and lead to others.
- In order to create a good simulation you must include the number of users, what they are doing, how often they are doing it, and when they are doing it.
- Performance testing and analysis needs to include consideration of beginning and end of shift activities, seasonal trends, and special events (e.g. 2 am backup activity).
- Ignore the code until after you've looked at the lower layers of the box.
- Any analysis of code performance should use a profiler as a guide.
- An improperly configured JVM that artificially resource starves an application will likely have a huge negative impact on application performance.
- The CPU can only process so many instructions per second, memory can only hold so much data, I/O channels are limited data transfer rates, disks have a fixed capacity.
- The first step in performance analysis is to analyse the 4 primary resources, CPU, memory, disk and network I/O.
- Normally we would like system CPU utilization to be less than 20% of total (the rest should be application or "user" CPU utilization). If more than that is used, try to analyze what the kernel is doing (possibly for the application). Tasks performed by the kernel include: context switching, thread scheduling, memory management, interrupt handling.
- System memory management uses CPU and possibly disk I/O too - high system CPU utilization can be due to excessive memory management, but that is rare. Low system CPU utilization can also be due to excessive memory management if accompanied by a lot of disk activity. In the latter case, paging identfies the problem.
- High system CPU utilization can be due to excessive context switching of threads - perhaps too many threads or too much locking and switching between threads is occurring.
- I/O bound and lock bound applications can leave the CPU underutilized - CPU utilization can actually decrease as the load increases. This should be accompanies by a highe proportion of system CPU utilization compared to non-system CPU utilization.
- An improperly sized heap will cause you JVM to do a lot more work than is necessary.
- Measure the efficiency of the garbage collector by setting -Xverbose:gc flag on the command line and analysing the resulting output.
- GC efficiency is defined as the time spent in garbage collection over the running time of the application. A GC efficiency greater than 10% is an indication that one needs to tune the JVM heap.
- If CPU utilization is high and GC is running ok then it is most likely that an algorithmic inefficiency is at fault, and the code needs profiling.
- Thread pooling works to limit the level of activity in your application by limiting the number of requests it can handle. The upside of thread pooling is that a system under load should maintain maximal throughput, though some requests may have to wait a long time to be serviced.
- Sizing the thread pool is a tunable parameter that can have dramatic effect on performance. Too large a pool and you can overload the box, causing lost efficiency from context switching. Too small a pool and there will be requests that could be processed that won't be, causing response times.
- Compare the complete round trip time of a request with the server's internal response time for a given request. If there is a large gap that cannot be accounted for with network latency, than most likely your thread pool is too small.
- Use an analysis of the lower layers of the system, i.e. operating system performance monitoring, to initiate and guide your analysis of the overall system.
The Law of South African Crime (Page last updated September 2007, Added 2007-11-28, Author Dr. Heinz M. Kabutz, Publisher ). Tips:
- There are three ways letting a field be correctly visible across multiple threads: use synchronized, volatile, or final.
- Making a field volatile will ensure that threads always read the value from the field and do not cache it locally.
- Operations such as ++ and -- are not atomic so making a field volatile is not sufficient to let fields be operated on using ++ and -- and still guarantee consistency of values across threads.
- Making a field final guarantees that the value it holds will be consistent across threads, but obviously cannot be used for fields that need updating.
- Incorrectly synchronized code can run correctly most of the time, but fail when running during high load.
Back to newsletter 084 contents
Last Updated: 2018-02-27
Copyright © 2000-2018 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