[REP Index] [REP Source]

REP:121
Title:Automatic unloading of libraries for pluginlib
Author:Dirk Thomas
Status:Final
Type:Standards Track
Content-Type:text/x-rst
Created:6-Feb-2012
ROS-Version:Fuerte
Post-History:6-Feb-2012

Abstract

In REP 116 [1] pluginlib was enhance to support unloading libraries within the life cycle of the ClassLoader. In this REP the interface the user of pluginlib uses is revised to better support the load/create/unload cycle of shared libraries in order to permit unloading the library from memory when it is no more used.

Current implementation

The ClassLoader of pluginlib exposes the following methods:

  • loadLibraryForClass(const std::string& lookup_name) Loads the library (if not already loaded) and increments a counter which is specific for that library.
  • unloadLibraryForClass(const std::string& lookup_name) Decrements the counter of that library and unloads the library if the counter reaches zero.

These two methods provide a clear interface and semantic regarding the life cycle of libraries.

In order to instantiate a class from a library the user calls:

  • T* createClassInstance(const std::string& lookup_name, bool auto_load = true) Creates an instance of type T and returns a pointer. The ownership of the object is transfered to the caller. If autoloading is disabled the pointer might be null if the library has not been loaded before. If autoloading is enabled (default) the library is only loaded if it has not been loaded before.

The issue with this implementation is that the user has no indication if createClassInstance() increased the library counter implicitly or not. Furthermore the user has to take care about the correct point in time when calling unloadLibraryForClass(). If two different entities are working with the same ClassLoader instance the library might get unloaded while it is still in use (i.e. A calling loadLibraryForClass(), B calling createClassInstance(), A calling unloadLibraryForClass(), results in unloading the library).

Specification

In order to not break existing code which relies on this current implementation detail the behavior of it can not be changes and is therefore deprecated (and later on removed).

Instead two new methods are introduced which provide a clear semantic for creating instances and handling the life cycle of the create instance.

  • boost::shared_ptr<T> createInstance(const std::string& lookup_name)
  • T* createUnmanagedInstance(const std::string& lookup_name)

Internally both will always call loadLibraryForClass() which ensures that the reference counter for the library is increased for every instance.

For createInstance() the ownership stays with the callee (the ClassLoader) and deleting and unloading is triggered by the deleter of the boost shared pointer. For createUnmanagedInstance() the ownership and responsibility to unload the library is transfered to the caller.

The common usage patterns would be:

  • Use createInstance() (once or multiple times) and let the boost deleter take care about deleting the instance and unloading the library.

or

  • Use createUnmanagedInstance() (once or multiple times) and manually delete the instance later and call unloadLibraryForClass() for each garbaged instance. This approach is usually used when the ownership of the instances should be passed to something else (i.e. when using Qt objects).

or

  • Wrap multiple create calls between one loadLoadForClass() and one unloadLoadForClass() to keep library loaded for a longer time (even if no instance are currently loaded).

Backwards Compatibility

The side effects of the existing and createCreateInstance() method in combination with unloadLoadForClass() are not fixable without potentially breaking existing application. Therefore the implementation of createClassInstance() is not altered in any way but deprecated. The additions will induce no effect on existing code.

The previous option to create an instance with autoloading disabled is not necessary since that case can be easily queried before and only conditionally call one of the create methods.

Reference implementation

Reference implementation code is locate in the HG repository. See the current version of the interface [2] and the implementation [3] for detailed information.