Welcome!

Java Authors: Maureen O'Gara, Bruce Armstrong, Liz McMillan, Walter H. Pinson, III, Yakov Werde

Related Topics: Java

Java: Article

The Right Time for Real Time Java

Addressing the sources of unpredictability in Java applications

In JIT compilation mode, the mode in which a virtual machine, like the HotSpot JVM, always executes, compilation is triggered during the execution of the program when certain internal counters reach specified limits. This mode is designed to be optimal in a non-real-time system.

Since JIT compilation cannot be controlled, Java RTS also provides an ITC mode. This mode allows you to control when specified classes will be compiled, thereby ensuring that compilation will not interfere with the execution of time-critical code. In ITC mode, specified classes are pre-loaded and marked for ITC compilation. When such a class is initialized, some or all of its methods are compiled. You specify these classes and methods in a list that is passed as a command-line argument. You can also ask Java RTS to create the list for you. By specifying that methods in critical code sections are to be compiled at class initialization time, you can reduce or eliminate jitter caused by JIT compilation.

Java RTS also ensures that all symbols referenced by compiled code are resolved at compile time. In other words, it features eager symbol resolution. Classes may thus be indirectly loaded and initialized at ITC time.

Garbage Collection
A final source of jitter in virtual machines is GC. Non-real-time virtual machines typically provide several garbage collectors to choose from, depending on whether the goal is throughput or predictability. In order to maximize GC efficiency, high throughput collectors require that all application threads be suspended during a stop-the-world pause. Doing so, however, can occasionally cause long response times and correspondingly large jitter, which can be up to several orders of magnitude higher than typical response times. Alternatively, low pause time collectors, such as Hotspot’s Concurrent Mark Sweep collector, attempt to bound the length of stop-the-world pauses. They cannot, however, eliminate or truly bound them on a time-sharing system due to the unpredictability of the execution of the GC thread or threads. Such collectors also incur a throughput penalty because some GC work is done concurrently with normal program execution, stealing time from application threads and producing additional jitter for time-critical code. The throughput penalty with respect to non-concurrent collectors is typically 5–15 percent.

Java RTS supports two collectors, a non-real-time serial collector, also available in the Hotspot JVM, and a Real-Time Garbage Collector (RTGC). The RTGC can be configured to execute in a very deterministic manner, though it exhibits lower throughput than non-real-time collectors, particularly on uniprocessors. It also requires a larger heap because it recovers memory in relatively small chunks, which results in a larger object representation than that used in non-real-time collectors.

Some of the throughput penalty is due to extra time spent accessing object fields and array elements, while the rest is due to time taken by GC threads executing concurrently with the application. The precise amount of time varies with an application’s allocation rate but the throughput penalty, with respect to the serial collector, can range from a low of 10 percent to a high of 50 percent, in some cases.

Note, however, that the system is still scalable in the sense that any particular level of throughput can be achieved by adding more hardware. There is no intrinsic scalability limit using the RTGC.

The function of the RTGC is based on the criticality of both application and GC threads as defined at the beginning of this article. Java RTS real-time threads can be deemed critical or non-critical, whereas non-real-time threads (java.lang.Thread instances) are non-critical by definition. The highest priority at which an RTGC thread can execute is called the RTGC critical priority. The thread types in Java RTS are:

  • No-heap real-time threads (NHRTs): These threads are instances of the RTSJ class javax.realtime.NoHeapRealtimeThread and they exhibit hard real-time behavior. They are critical by definition and must execute within defined time limits (a few tens of microseconds). These threads cannot allocate memory from the Java heap. As a result, they don’t interact with GC at all. i.e., they don’t depend on GC freeing up memory for their correct operation nor are they subject to GC-induced jitter. NHRTs run at a priority higher than the priority of any other threads in the system, so care must be taken that they don’t consume all available CPU resources; otherwise, the RTGC and/or non-NHRT threads might not operate correctly. Using them requires the use of Immortal and Scoped memory.
  • Critical real-time threads: These threads are instances of the RTSJ class javax.realtime.RealtimeThread (RTT) and also exhibit hard real-time behavior. Their priority is above the RTGC critical priority and they execute within defined time limits (a few hundreds of microseconds), provided that the RTGC is correctly configured. These threads must also not consume all CPU resources, because that would prevent the RTGC from recycling memory, resulting in memory exhaustion that would cause application threads to block on allocation.
  • Non-critical real-time threads: These threads are also instances of the RTSJ class javax.realtime.RealtimeThread (RTT), but they exhibit soft real-time behavior. Their priority is below the RTGC critical priority and they don’t necessarily execute within defined time limits. Critical and non-critical real-time threads are not the same type of threads but setting their priorities in the context of the RTGC determines whether they behave as hard or soft real-time threads.
  • Non-real-time threads: These are instances of the java.lang.Thread class (JLT) and are non-critical by definition.

The programmer must set thread priorities to reflect the criticality of any thread in a Java RTS application. Figure 1 shows the priority levels for the RTGC and for the different thread types.

More Stories By Paul Hohensee

Paul Hohensee is a senior staff engineer at Sun Microsystems where he is the Java Platform Standard Edition JVM Technical Lead. His primary focus is JVM performance along with hardware and platform support for Java and other dynamic languages. Earlier in his career he worked on dynamic binary translation as well as optimizing compilers and libraries for the first symmetric multiprocessors.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.