You can designate a component as reusable, or persistent, so that the
infrastructure does not need to create a new instance of the execution
class every time the component is to be run. To designate a component
as reusable, define a component property named “reusePolicy” with
the value of “any” (the default value is “none”). When a component
has this designation, the infrastructure may use the same class instance
for multiple executions. The system is not required to reuse a class
instance. This feature gives the system the flexibility to reuse a class
instance if it is beneficial for performance or memory reasons. When
a component has a reusePolicy of “any,” the component lifecycle is:
- The no-argument constructor is called to create an instance of the
class.
- initialize().
- Repeat the following execution sequence for each execution:
- configEnvironment().
- preExecute().
- execute().
- postExecute().
- destroy().
In this case some of the component methods are called multiple times,
once for each execution of the component. Component reuse is always serial.
Once the execution sequence starts (with a call to configEnvironment()
),
the sequence will complete, ending with postExecute()
, before another
call will be made to start the execution sequence again. As in the nonreuse
case, the system guarantees that all calls to these methods are made
one at a time and on the same JVM thread.
At any time when the component instance is not in the execution sequence
(for example, postExecute()
was the last method called), the system may
choose to call the destroy()
method and remove all its references to
the instance. Later the JVM may garbage collect the instance. However,
in general, the system will not destroy an existing instance; it will
remain persistent until the SIMULIA Execution Engine
station is stopped or the Isight
Gateway is closed (local Isight
execution).
Persistent components can be useful when the component needs to perform
some long-running initialization one time (e.g., starting an external
application process). Performing a long-running initialization can be
done once in the initialize()
method; the external application can then
be used over and over again for different executions (assuming the application
supports that type of usage and does not have to be restarted for each
usage). Typically, the destroy()
method would be used to release whatever
resources were allocated in the initialize()
method, such as closing
and external application process.
Even when a component is persistent and reusable, the system may still
create multiple instances to run at the same time. For example, in the
SIMULIA Execution Engine
distributed execution environment a station may be requested to execute
the same component for two users running different models. The system
might not wait for one to complete before starting another. It may create
two instances that will execute at the same time, each on their own thread.
If the component cannot support multiple concurrent instances, it can
limit the number of instances the system will create. For more information,
see Limiting Component Instances.
For a component class to be safe for this type of repeated execution,
it must be serially reusable. In effect, it must “forget” everything
from one execution cycle to the next. If it fails to ignore data from
a prior execution, the data may “pollute” or corrupt data in a subsequent
execution. In Java programming terms, the following guidelines should
be followed by the component class and any classes it calls directly
or indirectly:
- The component class and any classes it calls should have no STATIC
fields.
- It is best if the class has no fields (class level variables) at all
because they are a risk item for serial reuse. Most components can avoid
the use of class fields by passing arguments to methods instead of passing
data through fields; which is better programming practice anyway.
- If the class does have field variables, the value of each field must
be initialized either in the
preExecute()
method, if there is one, or
as the first thing done in the execute()
method to ensure that any old
values left in these fields from a prior execution cannot influence or
corrupt the next execution cycle. Every class field must be initialized
or reinitialized for every cycle. - In either the
postExecute()
method, if there is one, or as the last
thing done in the execute()
method, all object references held in class
fields should be set to NULL
. Class fields must be set to NULL
because
the class instance may remain unused between executions for a long period
of time. The Java garbage collector will be unable to release any memory
associated with objects referenced by the class fields unless the fields
have been set to NULL
. - If the component calls non-Java native code (JNI), that native code
must also be serially reusable. It should also be designed to release
memory at the end of each component execution cycle.