See:
Description
| Packages | |
|---|---|
| javax.realtime | |
This section defines classes directly related to memory and memory management. These classes:
Schedulable objects that use the enter method of MemoryArea behave effectively as if they kept the memory areas they enter in a scope stack which enter pushes and pops.
This chapter defines memory area classes. Two memory areas may be associated with each MemoryArea instance, the memory area containing the instance and the backing memory that contains memory managed by the MemoryArea instance.
Some memory area classes implement portals. These are a tool that associates a reference value with a memory area. It is normally used to give code that has a reference to the memory area a way to go from that to a reference to an object stored in that memory area.
For purposes of scoped memory reference counting, the following are treated as execution contexts:
RealtimeThread objects that have been started and have not terminated,
The initial memory area for a schedulable object is non-default if it is not the memory area where the schedulable object was created.
An AsyncEventHandler is fireable whenever there is an agent that can release it. This includes cases when the AsyncEventHandler is:
The following list establishes the semantics and requirements that are applicable across the classes of this section. Semantics that apply to particular classes, constructors, methods, and fields will be found in the class description and the constructor, method, and field detail sections.
MemoryArea class. When a memory area, m, is entered by calling m.enter (or another method from the family of enter-like methods in MemoryArea or ScopedMemory) m becomes the allocation context of the current schedulable object. When control returns from the enter method, the allocation context is restored to the value it had immediately before enter was called.
newInstance and newArray methods.
MemoryArea and ScopedMemory classes: all the enter and joinAndEnter methods, executeInArea, and both newInstance methods. See the semantics in Maintaining the Scope Stack for details.
executeInArea, newInstance and newArray methods, when invoked on an instance of ScopedMemory require that instance to be an outer allocation context on the current schedulable object's current scope stack.
ScopedMemory is said to be in use if it has a non-zero reference count as defined by semantic (17) below.ScopedMemory object becomes in use, its parent is the nearest ScopedMemory object outside it on the current scope stack. If there is no outside ScopedMemory object in the current scope stack, the parent is the primordial scope which is not actually a memory area, but only a marker that constrains the parentage of ScopedMemory objects.
RealtimeThread, it completes execution
IllegalAssignmentError.
executeInArea, and the newInstance and newArray methods from the ImmortalMemory and HeapMemory classes. These methods allow it to execute with an immortal current allocation context, but semantic (15) applies even during execution of these methods.
ScopedMemory or its subclasses must maintain a reference count which is greater than zero if and only if either:
AsyncEventHandler.
AsyncEventHandler becomes non-fireable, that real-time thread or AsyncEventHandler is considered in control of the scope and must execute the finalizers.runFinalizersOnExit, the system need not execute finalizers for immortal objects that remain unfinalized when the JVM begins termination.
ImmortalMemory.instance().executeInArea(r) where r is a Runnable that executes the <clinit> method of the class being initialized.
|
Stored In
|
Reference
to Heap |
Reference
to Immortal |
Reference to Scoped
|
null
|
|---|---|---|---|---|
|
|
|
|
|
Permit |
|
|
|
|
|
Permit |
|
|
|
Permit
|
Permit, if the reference is from the same scope, or an outer scope
|
Permit |
|
|
|
|
|
Permit |
For this table, ImmortalMemory and ImmortalPhysicalMemory are equivalent, and all sub-classes of ScopedMemory are equivalent.
The scope stack is implicitly visible through the assignment rules, and the stack is explicitly visible through the static getOuterMemoryArea(int index) method on RealtimeThread.
Four operations effect the scope stack: the enter methods in MemoryArea and ScopedMemory, construction of a new schedulable object, the executeInArea method in MemoryArea, and the new instance methods in MemoryArea.
ma, is entered by calling a ma.enter method, ma is pushed on the scope stack and becomes the allocation context of the current schedulable object. When control returns from the enter method, the allocation context is popped from the scope stack
m, is entered by calling m's executeInArea method or one of the m.newInstance methods the scope stack before the method call is preserved and replaced with a scope stack constructed as follows:
ma is a scoped memory area the new scope stack is a copy of the schedulable object's previous scope stack up to and including ma.
ma is not a scoped memory area the new scope stack includes only ma.
executeInArea method, the scope stack is restored to the value it had before ma.executeInArea or ma.newInstance was called.
Notes:
Forma.enter(logic):push ma on the scope stack belonging to the current schedulable object -- which may throw ScopedCycleException execute logic.run method pop ma from the scope stack
if ma is an instance of heap immortal or
ImmortalPhysicalMemory
start a new scope stack containing only ma
make the new scope stack the scope stack for
the current schedulable object
else ma is scoped
if ma is in the scope stack for the
current schedulable object
start a new scope stack containing ma and all
scopes below ma on the scope stack.
make the new scope stack the scope stack for
the current schedulable object
else
throw InaccessibleAreaException
execute logic.run or construct the object
restore the previous scope stack for the
current schedulable object
discard the new scope stack
cma with initial memory area of ima:
if cma is heap, immortal or ImmortalPhysicalMemory
create a new scope stack containing cma
else
start a new scope stack containing the
entire current scope stack
if ima != cma
push ima on the new scope stack --
which may throw ScopedCycleException
The above pseudocode illustrates a straightforward implementation of this specification's semantics, but any implementation that behaves effectively like this one with respect to reference count values of zero and one is permissible. An implementation may be eager or lazy in maintenance of its reference count provided that it correctly implements the semantics for reference counts of zero and one.
The parent of a scoped memory area is identified by the following rules (for a stack that grows up):
The operational effect of the single parent rule is that when a scoped memory area has a parent, the only legal change to that value is to "no parent." Thus an ordering imposed by the first assignments of parents of a series of nested scoped memory areas is the only nesting order allowed until control leaves the scopes; then a new nesting order is possible. Thus a schedulable object attempting to enter a scope can only do so by entering in the established nesting order.
Each scoped memory has a reference to its parent memory area, ma.parent. The parent reference may indicate a specific scoped memory area, no parent, or the primordial parent.
If a scoped memory area is the non-default initial memory area of an async event handler, or the non-default initial memory area of a real-time thread that has not terminated, it is referred to as pinned.
precondition: ma.parent is set to the correct parent
(either a scoped memory area or the primordial scope)
or to noParent
t.scopeStack is the scope stack of
the current schedulable object
if ma is scoped
parent = findFirstScope(t.scopeStack)
if ma.parent == noParent
ma.parent = parent
else if ma.parent != parent
throw ScopedCycleException
else
t.scopeStack.push(ma)
findFirstScope is a convenience function that looks down the scope stack for the next entry that is a reference to an instance of ScopedMemoryArea.
findFirstScope(scopeStack) {
for s = top of scope stack to
bottom of scope stack
if s is an instance of scopedMemory
return s
return primordial scope
}
ma = t.scopeStack.pop() if ma is scoped if !(ma.in_use || ma.pinned) ma.parent = noParent
Languages that employ automatic reclamation of blocks of memory allocated in what is traditionally called the heap by program logic also typically use an algorithm called a garbage collector. Garbage collection algorithms and implementations vary in the amount of non-determinacy they add to the execution of program logic. Rather than require a garbage collector, and require it to meet real-time constraints that would necessarily be a compromise, this specification constructs alternative systems for "safe" management of memory. The scoped and immortal memory areas allow program logic to allocate objects in a Java-like style, ignore the reclamation of those objects, and not incur the latency of the implemented garbage collection algorithm.
The term scope stack might mislead a reader to infer that it contains only scoped memory areas. This is incorrect. Although the scope stack may contain scoped memory references, it may also contain heap and immortal memory areas. Also, although the scope stack's behavior is specified as a stack, an implementation is free to use any data structure that preserves the stack semantics.
This specification does not specifically address the lifetime of objects allocated in immortal memory areas. If they were reclaimed while they were still referenced, the referential integrity of the JVM would be compromised which is not permissible. Recovering immortal objects only at the termination of the application, or never recovering them under any circumstances is consistent with this specification.
If a scoped memory area is used by both heap and non-heap SOs, there could be cases where a finalizer executed in non-heap context could attempt to use a heap reference left by a heap-using SO. The code in the finalizer would throw a memory access error. If that exception is not caught in the finalizer, it will be handled by the implementation so finalization will continue undisturbed, but the problem in finalizer that caused the illegal memory access could be hard to locate. So, catch clauses in finalizers for objects allocated in scoped memory are even more useful than they are for normal finalizers.