Real-Time Java Programming: RT-GC versus RTSJ ?
Here is my first weblog on Real-Time Java™ issues. Well, this is
in fact my very first weblog and I hope you will be forgiving. To
make it even worse, English is not my native language... I'm french
Let's start with a few words about myself to explain while I am the one writing this weblog. I have been working for ten years on ports and implementations of Java Virtual Machines, both for servers and embedded systems. Two years ago, I joined Sun Microsystems to work with Greg Bollella on the implementation of the Real-Time Java Specification™ (RTSJ) on top of HotSpot™ (go to http://java.sun.com/j2se/realtime/ for more information). As the most senior engineer of the team, I participated to the design of most of the components and I was in charge of their global integration. The major part of my contributions was on the memory management, particularly the new memory model based on ScopedMemory, which allows hard real-time threads to allocate memory without relying on the garbage collector. I am now focusing on the alternative, real-time garbage collection. In addition to the knowledge of the JVM, the team has been interacting with a lot of early access customers, both during training sessions and on the feedback mailing lists.
As a result, I am aware of the limits and the defaults of both
real-time garbage collection and ScopedMemory !
Fortunately, each
approach has a few advantages and I do believe they are
complementary. I'll explain it further in future weblogs.
For now, let's just say that we initially focused on ScopedMemory to prove that we could achieve with the Java language a behavior as deterministic as what is doable with other languages (response times in the 10 to 20 microseconds range). This is done while keeping most of the advantages of the Java language, including the safety of the memory management, which prevents memory corruption. Of course, there is no free lunch. The drawback is that to offer this safety without impacting the response times, constraints had to be added to the programming model. The alternative is to use real-time garbage collection. Response times go up to a few milliseconds. If this is sufficient for your needs, you may have to pay for CPU and memory overhead induced by the GC but it is worth the price in terms of productivity. As a conclusion on the memory management, use ScopedMemory only if real-time garbage collection does not fulfill your needs.
However, the important message in this weblog is that the RTSJ is not only about memory management. A lot of people think that having a real-time garbage collector will be sufficient to solve their real-time needs. My opinion is that the reasons that made them choose the Java language should also make them consider using the RTSJ. The gap between the Java languages and the other languages comes from:
- a portable programming environment with a very rich set of libraries
- a very robust runtime environment, with dynamic checks allowing users to recover from unexpected errors.
First, in terms of libraries, the RTSJ provides a very rich set of APIs... too rich to explain in a single weblog. For instance, the RTSJ provides first-grade support for asynchronous activities. Imagine that instead of providing a single handler to a limited set of POSIX signal, you can create new events and attach several handlers to each of them. In addition, each handler can run at a different priority and you can do anything you want into these handlers... including blocking! It will be up to the Java Virtual Machine to optimize the resources and efficiently create/schedule/recycle execution environments for these handlers. This goes much further than what other real-time programming environments offer. Another API that is worth mentioning is the RawMemoryAccess API. Instead of having to write your own native method to access a physical resource (like a device), it can be done with a Java method. Since this is a standard API, a smart compiler will be able to inline this API call, making it much more efficient than a native call.
However, the real gain of the RTSJ is that all these APIs include dynamic checks that allow you to detect and solve temporal issues. This is particularly important if you consider that temporal issues are much more complex and unpredictable than for instance null pointer or array index errors. Even better, a lot of these temporal issues are automatically solved. For instance, you can manage CPU burst due to the arrival of a huge flow of events. For each handler, you can easily specify what to do if it is released too frequently. You can for instance let the system ignore or defer the following releases. This allow you to easily define the worst-case CPU overhead due to the handling of asynchronous events. In fact, an implementation of the RTSJ can optionally provide a feasibility algorithm that checks that you always have enough CPU power to execute the periodic threads and aperiodic handlers you have defined. Even without the feasibility analysis, a JVM must at least provide deadline miss detection. Hence, if a thread does not get enough CPU to perform its work, you can easily register a (higher priority) handler to take a corrective action and keep your system stable. I think that with respect to robustness, this single feature is sufficient to justify using the RTSJ !
As a conclusion, whether you switched to Java for the portability of
its environment or for its execution robustness, you should consider
using the RTSJ for similar reasons (provided you have real-time
constraints
). Do not get afraid because of ScopedMemory. Its use
can be limited to a small subset of your program... and completely
avoided if a real-time garbage collector is sufficient for your needs.
In fact, my feeling is that it would be even better to mix the two
approaches, using ScopedMemory only for the hardest of your hard
real-time threads (to achieve the smallest possible deadlines and be
confident you will always get the memory you need in these critical
threads). I'll try to convince you in future weblogs.