Design Article
Improve Real-Time Java performance and reliability with ScopedMemory Allocation: Part 1
Kelvin Nilsen, Ph.D., Aonix
10/14/2007 3:30 PM EDT
Real-time Java programs instantiate ScopedMemory allocation contexts within which temporary objects are allocated. After all threads exit a ScopedMemory context, all of the objects allocated within that context are instantly reclaimed without any need for traditional garbage collection tracing.
Using the ScopedMemory programming abstractions as an alternative to garbage collection has proven very difficult. ScopedMemory programming errors result in reliability problems because program components terminate with various run-time exceptions.
Maintenance of software and composition of independently developed software components are especially difficult because the ScopedMemory assumptions upon which each component's validity depends are not documented nor enforced in the interface description of the component.
This article describes a system of Java 5.0 style annotations which enables static analysis tools to prove that ScopedMemory protocols are followed correctly within methods that make use of ScopedMemory objects. These annotations also make it possible to automatically determine the size of each ScopedMemory allocation context as required for reliable operation of the code that allocates objects within the scope.
Though these annotations have been designed specifically to support the development and certification of safety-critical Java code, their use is also relevant to the development and maintenance of hard real-time mission-critical code. The principles are illustrated with various code samples.
Some Historical Context
The use of Java with real-time garbage collection as an implementation
language for soft real-time systems has now been proven in a large
number of successful mission-critical deployments with millions of
hours of 5-9's reliability.
This technology delivers full access to traditional Standard Edition Java libraries and off-the-shelf components available under both commercial and open-source licensing terms. Statistical analysis demonstrates that these systems provide reliable compliance with real-time constraints as low as a single millisecond.
However, there are several reasons why this particular technology has not penetrated into the deepest levels of embedded real-time systems:
1) Standard Edition Java enhanced with real-time garbage collection runs significantly slower (up to three times slower) than optimized C code for CPU-intensive activities that are typical of low-level operations such as radar and sonar signal processing, software-defined radios, global positioning systems, and so forth.
2) The minimum footprint for effective deployment of a Standard Edition Java application is several megabytes, much too large for certain memory- and power-constrained embedded devices.
3) Though it may be theoretically possible to prove that a garbage-collected Java application satisfies hard real-time timing constraints, the complexity of the real-time garbage collection algorithms and the subtle interplay between garbage collection and application behavior makes such proofs extremely difficult to develop and maintain in the face of software evolution.
Also, the sorts of problems that programmers deal with in the lowest layers of their embedded software hierarchies tend to be very static, and these programmers see little need for the generality of automatic garbage collection.
The emergence of the scoped-memory
alternative
When the Real-Time Specification for Java (RTSJ) was published in 2001,
it provided an alternative to the use of automatic garbage collection
for use in very low-level software.
This mechanism is known as scoped memory. Conceptually, a memory scope is a reusable memory region within which allocated temporary objects persist until the scope is no longer referenced by any program components.
At this point, all of the objects that had been allocated within the scope are reclaimed and the scope can be reused to serve the temporary memory allocation needs of another program component. To assure the absence of dangling pointers, memory scopes are organized as a stack.
The order in which scopes are reclaimed is the reverse of the order in which they are entered (LIFO). Objects allocated within inner-nested (more recently entered) scopes may refer to objects residing in more outer-nested scopes.
But if an attempt is made to create a reference from an object residing in an outer-nested scope to an object residing in an inner-nested scope, a run-time check associated with the assignment operation throws an IllegalAssignmentError exception.
This protocol assures that program execution will never result in dangling pointers, a common C and C++ bug that results when the memory for particular objects is reclaimed before all of the references to the reclaimed object have disappeared.



