Reusable and Persistent Components

Unless specifically designated otherwise, the component lifecycle is repeated for every execution of the component. A component may be run many times in the course of running a single model.

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:

  1. The no-argument constructor is called to create an instance of the class.
  2. initialize().
  3. Repeat the following execution sequence for each execution:
    1. configEnvironment().
    2. preExecute().
    3. execute().
    4. postExecute().
  4. 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.