[ 
https://issues.apache.org/jira/browse/UIMA-6413?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17479926#comment-17479926
 ] 

Richard Eckart de Castilho edited comment on UIMA-6413 at 1/21/22, 9:12 AM:
----------------------------------------------------------------------------

When a resource manager is copied using the {{ResourceManager_impl.copy()}} 
method, the {{UIMAClassLoader}} is copied along. If the copy of the resource 
manager is destroyed, then the {{UIMAClassLoader}} is currently closed - that 
means that the original resource manager can also no longer use the class 
loader. This seems to happen only in 
{{PearAnalysisEngineWrapper.createRM(StringPair, PackageBrowser, 
ResourceManager)}}.

{code}
     if (null == parentResourceManager) {
       // could be null for top level Pear not in an aggregate
       rsrcMgr = UIMAFramework.newDefaultResourceManager();
     } else {
       rsrcMgr = ((ResourceManager_impl) parentResourceManager).copy();
     }
     rsrcMgr.setExtensionClassPath(sp.classPath, true);
{code}

However, the call to {{rsrcMgr.setExtensionClassPath}} following the copy 
immediately in fact currently installs a new {{UIMAClassLoader}} in the copied 
resource manager.


was (Author: rec):
When a resource manager is copied using the {{ResourceManager_impl.copy()}} 
method, the {{UIMAClassLoader}} is copied along. If the copy of the resource 
manager is destroyed, then the {{UIMAClassLoader}} is currently closed - that 
means that the original resource manager can also no longer use the class 
loader. This seems to happen only in 
{{PearAnalysisEngineWrapper.createRM(StringPair, PackageBrowser, 
ResourceManager)}}.

{code}
     if (null == parentResourceManager) {
       // could be null for top level Pear not in an aggregate
       rsrcMgr = UIMAFramework.newDefaultResourceManager();
     } else {
       rsrcMgr = ((ResourceManager_impl) parentResourceManager).copy();
//       newPearsParent.set((ResourceManager_impl) parentResourceManager);
//       rsrcMgr = UIMAFramework.newDefaultResourceManagerPearWrapper();
//       newPearsParent.remove();
//       
((ResourceManagerPearWrapper)rsrcMgr).initializeFromParentResourceManager(parentResourceManager);
     }
     rsrcMgr.setExtensionClassPath(sp.classPath, true);
{code}

However, the call to {{rsrcMgr.setExtensionClassPath}} following the copy 
immediately in fact currently installs a new {{UIMAClassLoader}} in the copied 
resource manager.

> Memory leak in FSClassRegistry
> ------------------------------
>
>                 Key: UIMA-6413
>                 URL: https://issues.apache.org/jira/browse/UIMA-6413
>             Project: UIMA
>          Issue Type: Improvement
>          Components: Core Java Framework
>            Reporter: Richard Eckart de Castilho
>            Assignee: Richard Eckart de Castilho
>            Priority: Major
>             Fix For: 3.3.0SDK
>
>
> This is essentially a follow-up issue to UIMA-6276.
> So, when a CAS is created, then a cache is filled in 
> {{FSClassRegistry.cl_to_type2JCas}} which maintains information about the 
> JCas representation of the different types. This is a per-classloader cache - 
> so for every classloader which is involved in the creation of a (J)CAS, an 
> entry is added. Now normally, classloaders are pretty long-lived objects and 
> you only have so many during the runtime of a program. But there are cases 
> where classloaders are created in volumes and in this case we run into 
> trouble. Now, UIMA-6276 has turned the cache into a weak map hoping that once 
> a classloader is garbarge-collected, the cache would get cleaned up 
> automatically. However, that idea was not thought through entirely because 
> one of the pieces of information stored in the map is a {{FsGenerator3}} and 
> that generator is actually generated via the particular classloader that is 
> the key in the map. Thus, a value in the map has a strong reference to the 
> weak key causing the key never to get garbage collected... and there might be 
> other fields as well contributing to that cycle.
> In particular, a new classloader is generated whenever a new 
> {{ResourceManager}} with a custom extension path. A typical case for this to 
> happen is when a PEAR is used. But there can be other reasons why somebody 
> would create new custom resource managers.
> Limiting the number of {{ResourceManager}}s in a system may not be feasible 
> because typically there should be one per pipeline (to allow for shared 
> resources), so if you are in a situation where pipelines are instantiated and 
> destroyed repeatedly, it makes sense to create {{ResourceManager}}s alongside.
> However, typically the number of classloaders in a system is pretty set. The 
> {{ResourceManager}} internally wraps these classloaders with an 
> {{UimaClassLoader}} (only if a specific classloader or a extension path is 
> passed to the resource manager). So assuming that essentially always the same 
> set of classloaders is provided (any maybe only a limited set of extension 
> paths), it should be ok to introduce another cache of {{[classloader, 
> extension path] -> UimaClassLoader}} to limit the number of 
> {{UimaClassLoader}} instances and therefore limit the size of 
> {{FSClassRegistry.cl_to_type2JCas}}.



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to