| Summary: | Memory leak when using XSD Metamodels in MWE Workflows | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Product: | [Modeling] EMFT | Reporter: | Daniel Luebke <eclipse> | ||||||
| Component: | MWE | Assignee: | Moritz Eysholdt <moritz.eysholdt> | ||||||
| Status: | RESOLVED FIXED | QA Contact: | |||||||
| Severity: | normal | ||||||||
| Priority: | P3 | CC: | jochen.schmich, moritz.eysholdt, sven.efftinge | ||||||
| Version: | unspecified | Flags: | moritz.eysholdt:
helios+
|
||||||
| Target Milestone: | RC2 | ||||||||
| Hardware: | PC | ||||||||
| OS: | Windows XP | ||||||||
| Whiteboard: | |||||||||
| Attachments: |
|
||||||||
Created attachment 169068 [details]
Hack for working around the memory leak
Please see Bug 310359 - Posted the same issue some weeks ago. *** Bug 310359 has been marked as a duplicate of this bug. *** Hi Daniel, As pointed out in Bug 310359, there is XSDMetaModel.mmRegistry, which is an (ugly) static variable which keeps the loaded meta models for the JVM's lifetime. I introduced this registry to be able to access an XSDMetaModel from within Xpand/Xtend via XMLReaderHelper.readXML(String, String). Sven, is there any way to access to current workflow context from within Xpand/Xtend? This seems to be a more appropriate context for this registry. Daniel, please note that mmRegistry is only populated with XSDMetaModels that have the ID-attribute specified. The ExecutionContext is the place to store any Xpand-global state. I opened up (made mutable) the global vars map just yesterday :-) The state is actually Worflow-global and no just Xpand-gobal: The XSDMetaModel is typically created before Xpand/Xtend-code is executed and lives on for all further runs of Xpand/Xtend in the same workflow. in that case the meta model seems to be the right place. Just removing the static keyword wouldn't work? Created attachment 169304 [details]
Fix-v1
This fixes the problem with the static mmRegistry by removing the registry. The use case that the registry was needed for is now handled by taking the MetaModel from Xtend's execution context.
Please review the patch.
Fixed in HEAD. Please verify if this solves the memory leaking issue. The fix will be available with the next build from Hudson and the RC2 release. |
Build Identifier: M20090917-0800 If you run a MWE workflow multiple times from a Java program and that workflow uses a XSDMetaModel component, the XSD files will be loaded multiple times and stay in memory. If deployed on the server-side, this will lead to serious problems. We diagnosed this problem with the SAP Memory Analyzer tool after we detected a memory leak in our generator. In our project, we introduced a workaround by subclassing the XSDMetaModel and caching the dynamic ecore metamodel based on the XSD files. This is only a hack. A better solution IMO would be see whether the namespace is already registered. However, it works for our case. The class looks like this: public class XsdCachedMetaModel extends XSDMetaModel { private static final Map<List<String>, XSDMetaModel> cache = new HashMap<List<String>, XSDMetaModel>(); private static synchronized XSDMetaModel getMetaModel(List<String> uris) { if(!cache.containsKey(uris)) { XSDMetaModel xsdMM = new XSDMetaModel(); for(String uri : uris) { xsdMM.addSchemaFile(uri); } cache.put(uris, xsdMM); } return cache.get(uris); } private List<String> uris = new ArrayList<String>(); public void addSchemaFile(String uri) { uris.add(uri); } @Override public EPackage[] allPackages() { return getMetaModel().allPackages(); } @Override public EFeatureMapEntryTypeImpl getEFeatureMapEntryType() { return getMetaModel().getEFeatureMapEntryType(); } @Override public XMLFeatureMapTypeImpl getEFeatureMapType(EClass aClass) { return getMetaModel().getEFeatureMapType(aClass); } @Override public EFeatureType getEFeatureType() { return getMetaModel().getEFeatureType(); } @Override public EMapEntryType getEMapEntryType(EClassifier innerType) { return getMetaModel().getEMapEntryType(innerType); } @Override public EMapType getEMapType(EClassifier innerType) { return getMetaModel().getEMapType(innerType); } @Override public Set<Type> getKnownTypes() { return getMetaModel().getKnownTypes(); } private XSDMetaModel getMetaModel() { return getMetaModel(uris); } @Override public Set<String> getNamespaces() { return getMetaModel().getNamespaces(); } @Override public QNameType getQNameType() { return getMetaModel().getQNameType(); } @Override public Type getType(Object obj) { return getMetaModel().getType(obj); } @Override public Type getTypeForEClassifier(EClassifier element) { return getMetaModel().getTypeForEClassifier(element); } @Override public Type getTypeForETypedElement(ETypedElement typedElement) { return getMetaModel().getTypeForETypedElement(typedElement); } @Override public Type getTypeForName(String typeName) { return getMetaModel().getTypeForName(typeName); } @Override public TypeSystem getTypeSystem() { return getMetaModel().getTypeSystem(); } @Override public XSDManager getXsdManager() { return getMetaModel().getXsdManager(); } @Override public boolean isRegisterPackagesGlobally() { return getMetaModel().isRegisterPackagesGlobally(); } @Override public boolean isSaveEPackages() { return getMetaModel().isSaveEPackages(); } @Override public void setRegisterPackagesGlobally(boolean registerPackagesGlobally) { getMetaModel().setRegisterPackagesGlobally(registerPackagesGlobally); } @Override public void setSavePackagesPath(String path) { getMetaModel().setSavePackagesPath(path); } @Override public void setTypeSystem(TypeSystem typeSystem) { getMetaModel().setTypeSystem(typeSystem); } @Override public String toString() { return getMetaModel().toString(); } } Reproducible: Always Steps to Reproduce: 1. Create workflow using XSDMetaModel 2. Run this workflow in a loop from a WorkflowRunner and print memory consumption 3. See memory consumption increase and finally the program exit with an OutOfMemoryException.