Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Re: StackOverflowError on EPackage Initialization
Re: StackOverflowError on EPackage Initialization [message #522450] Mon, 22 March 2010 16:45 Go to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33139
Registered: July 2009
Senior Member
Paul,

It's best to use the EMF newsgroup/forum, for EMF questions. I've added
it to the "to" list of the reply.


Paul Hoser wrote:
> Hi Everybody!
>
> I have a problem with my EMF model. I am getting a StackOverflowError
> when my EPackages are initialized. My model is rather large. It
> consists of about 150 packages each containing at least one classifier.
>
> Within the init() method of an EPackage the inter-depending EPackages
> are initialized recursively. The interdenpendencies of an EPackage are
> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
> like this:
>
> public DependencyHelper()
> {
> ...
> interDependencies = new ArrayList<GenPackage>();
> collectPackages(interDependencies, getGenModel().getGenPackages(),
> -1);
> interDependencies.remove(GenPackageImpl.this);
> ...
> }
>
>
>
> protected void collectPackages(List<GenPackage> result,
> List<GenPackage> genPackages, int depth)
> {
> if (depth == 0) return;
>
> for (GenPackage genPackage : genPackages)
> {
> if (genPackage.hasClassifiers())
> {
> result.add(genPackage);
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth - 1);
> }
> else
> {
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth);
> }
> }
> }
>
>
> This basically means that all EPackages within the model which contain
> classifiers are inter-depedenent to each other. If we had an example
> model containing three packages (MyPackage, YourPackage, OurPackage)
> we would get generated code like this:
>
>
>
> public class MyPackageImpl extends EPackageImpl implements MyPackage
> {
> ...
> public static MyPackage init() {
> ...
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class YourPackageImpl extends EPackageImpl implements YourPackage
> {
> ...
> public static YourPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class OurPackageImpl extends EPackageImpl implements OurPackage
> {
> ...
> public static OurPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
>
> ...
> }
> ...
> }
>
>
> If we would now access any of these EPackages, for instance the
> MyPackage, via the eINSTANCE field all three packages would be
> initialized recursively and we would get the following stacktrace:
>
> OurPackageImpl.init() line: 655
> OurPackage.<clinit>() line: 75
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> YourPackageImpl.init() line: 698
> YourPackage.<clinit>() line: 78
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> MyPackageImpl.init() line: 714
> MyPackage.<clinit>() line: 77
>
>
> If this is performed not only for three packages (as listed above) but
> for 150 the 64K of stack size are not sufficient anymore.
>
>
>
> SOLUTION PROPOSALS & QUESTIONS
> ------------------------------
>
> A possible solution would be to simply increase the stack size via the
> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
> need to support Java 1.5.
Surely there must be a way to increase the stack size on all JVMs. That
seems like a pretty basic thing.
>
> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>
>
> I thought of some options for solving this issue. Unfortunately, my
> knowledge of EMF internals is too little to decide if these approaches
> are reasonable or not.
>
> 1. Reducing the number of interdependencies
> The algorithm for calculating the set of inter-depending EPackages
> could be optimized.
> - Is this a reasonable approach?
Certainly we make assumptions that packages all generated from the same
GenModel are interdependent. We could compute that in more detail...
> - Or is it necessary to always initialize all EPackages as soon as one
> EPackage is initialized?
Only if they are mutually dependent.
> - What is the interdependency initialization required for?
So that the metadata itself can be hooked up properly. Imagine each
package with a class with a feature of a type from the other package.
You'd need to create each package, each class, and each feature, and
then hook up the cross references between them.
>
> 2. Make the Interdependency Initialization Non-Recursive
You need to initialize the things on which you depend before can can
initialize. Each package knows it's own dependencies...
> It could be possible to set a "inDependencyInitialization" flag which
> is set by the first EPackage initialized. Subsequent calls to init()
> in other EPackages could skip their interdependency initialization.
> - Again, is this reasonable?
I'm not sure I follow, but I'd be very reluctant to change a process
that's proven to be a hot spot for unusual bugs.
> - Would this approach lead to concurrency problems?
Without a doubt it would lead to some unanticipated problem...
>
> 3. Reduce the number of method-calls per initialization
> As the EPackageDescriptor accesses the eINSTANCE field within its
> getEPackage() method via reflection each EPackage initialization
> requires 10 method calls. This number could be reduced by providing a
> public getInstance() method for accessing the EPackage instance.
Again, this is scary code the relies on how classes are loaded lazily by
the JVM. The stack size doesn't depend on the size of the method, only
the size of the stack frames which is related to the number of variables....
> - Why was this complicated way of accessing the EPackage instance via
> the eINSTANCE field chosen?
You could look through the bugzilla history for the template to see how
this has evolved based on subtle problems.
> - Could this be substituted by a getInstance() method or would this
> introduce concurrency problems?
>
> I would really like to better understand the rational behind the
> design decisions made for the EPackage initialization and would
> appreciate any feedback on the above proposed solutions and their
> corresponding questions.
> Of course if anyone has a better idea on how to solve this
> StackOverflow problem, it is more than welcome.
>
> Thanks and best regards,
>
> Paul
Are you using nested packages? Is that necessary? How are your packages
separated across GenModels? Do you have three different GenModels?


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: StackOverflowError on EPackage Initialization [message #522585 is a reply to message #522450] Tue, 23 March 2010 09:08 Go to previous messageGo to next message
Paul Hoser is currently offline Paul HoserFriend
Messages: 4
Registered: March 2010
Junior Member
Hi Ed,

thanks for the quick response. Sorry, for using the wrong newsgroup.

My model does contain nested packages. The ecore file I am using is not
under my control. I am obtaining the ecore file from a standardization
consortia. I could post-process the ecore file but I would actually like
to keep the package structure as provided.

But would not having nested packages actually change anything? The
EpackageImpl.DependencyHelper simply gets all packages from a GenModel,
if they're nested or not.

public DependencyHelper()
{
...
interDependencies = new ArrayList<GenPackage>();
collectPackages(interDependencies,getGenModel().getGenPackag es(),-1);
interDependencies.remove(GenPackageImpl.this);
...
}



I am not using different GenModels. My packages are all within one big
GenModel.


Best regards,

Paul

On 22.03.2010 17:45, Ed Merks wrote:
> Paul,
>
> It's best to use the EMF newsgroup/forum, for EMF questions. I've added
> it to the "to" list of the reply.
>
>
> Paul Hoser wrote:
>> Hi Everybody!
>>
>> I have a problem with my EMF model. I am getting a StackOverflowError
>> when my EPackages are initialized. My model is rather large. It
>> consists of about 150 packages each containing at least one classifier.
>>
>> Within the init() method of an EPackage the inter-depending EPackages
>> are initialized recursively. The interdenpendencies of an EPackage are
>> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
>> like this:
>>
>> public DependencyHelper()
>> {
>> ...
>> interDependencies = new ArrayList<GenPackage>();
>> collectPackages(interDependencies, getGenModel().getGenPackages(), -1);
>> interDependencies.remove(GenPackageImpl.this);
>> ...
>> }
>>
>>
>>
>> protected void collectPackages(List<GenPackage> result,
>> List<GenPackage> genPackages, int depth)
>> {
>> if (depth == 0) return;
>>
>> for (GenPackage genPackage : genPackages)
>> {
>> if (genPackage.hasClassifiers())
>> {
>> result.add(genPackage);
>> collectPackages(result, genPackage.getNestedGenPackages(), depth - 1);
>> }
>> else
>> {
>> collectPackages(result, genPackage.getNestedGenPackages(), depth);
>> }
>> }
>> }
>>
>>
>> This basically means that all EPackages within the model which contain
>> classifiers are inter-depedenent to each other. If we had an example
>> model containing three packages (MyPackage, YourPackage, OurPackage)
>> we would get generated code like this:
>>
>>
>>
>> public class MyPackageImpl extends EPackageImpl implements MyPackage
>> {
>> ...
>> public static MyPackage init() {
>> ...
>> YourPackageImpl theYourPackage = (YourPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>> instanceof YourPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>> YourPackage.eINSTANCE);
>> OurPackageImpl theOurPackage = (OurPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>> OurPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>> OurPackage.eINSTANCE);
>> ...
>> }
>> ...
>> }
>>
>> public class YourPackageImpl extends EPackageImpl implements YourPackage
>> {
>> ...
>> public static YourPackage init() {
>> ...
>> MyPackageImpl theMyPackage = (MyPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>> MyPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>> MyPackage.eINSTANCE);
>> OurPackageImpl theOurPackage = (OurPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>> OurPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>> OurPackage.eINSTANCE);
>> ...
>> }
>> ...
>> }
>>
>> public class OurPackageImpl extends EPackageImpl implements OurPackage
>> {
>> ...
>> public static OurPackage init() {
>> ...
>> MyPackageImpl theMyPackage = (MyPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>> MyPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>> MyPackage.eINSTANCE);
>> YourPackageImpl theYourPackage = (YourPackageImpl)
>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>> instanceof YourPackageImpl ?
>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>> YourPackage.eINSTANCE);
>>
>> ...
>> }
>> ...
>> }
>>
>>
>> If we would now access any of these EPackages, for instance the
>> MyPackage, via the eINSTANCE field all three packages would be
>> initialized recursively and we would get the following stacktrace:
>>
>> OurPackageImpl.init() line: 655 OurPackage.<clinit>() line: 75
>> Unsafe.ensureClassInitialized(Class) line: not available [native
>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>> Field.acquireFieldAccessor(boolean) line: 918
>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>> EPackageRegistryImpl.getEPackage(String) line: 133
>> YourPackageImpl.init() line: 698 YourPackage.<clinit>() line: 78
>> Unsafe.ensureClassInitialized(Class) line: not available [native
>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>> Field.acquireFieldAccessor(boolean) line: 918
>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>> EPackageRegistryImpl.getEPackage(String) line: 133
>> MyPackageImpl.init() line: 714 MyPackage.<clinit>() line: 77
>>
>> If this is performed not only for three packages (as listed above) but
>> for 150 the 64K of stack size are not sufficient anymore.
>>
>>
>>
>> SOLUTION PROPOSALS & QUESTIONS
>> ------------------------------
>>
>> A possible solution would be to simply increase the stack size via the
>> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
>> need to support Java 1.5.
> Surely there must be a way to increase the stack size on all JVMs. That
> seems like a pretty basic thing.
>>
>> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>>
>>
>> I thought of some options for solving this issue. Unfortunately, my
>> knowledge of EMF internals is too little to decide if these approaches
>> are reasonable or not.
>>
>> 1. Reducing the number of interdependencies
>> The algorithm for calculating the set of inter-depending EPackages
>> could be optimized.
>> - Is this a reasonable approach?
> Certainly we make assumptions that packages all generated from the same
> GenModel are interdependent. We could compute that in more detail...
>> - Or is it necessary to always initialize all EPackages as soon as one
>> EPackage is initialized?
> Only if they are mutually dependent.
>> - What is the interdependency initialization required for?
> So that the metadata itself can be hooked up properly. Imagine each
> package with a class with a feature of a type from the other package.
> You'd need to create each package, each class, and each feature, and
> then hook up the cross references between them.
>>
>> 2. Make the Interdependency Initialization Non-Recursive
> You need to initialize the things on which you depend before can can
> initialize. Each package knows it's own dependencies...
>> It could be possible to set a "inDependencyInitialization" flag which
>> is set by the first EPackage initialized. Subsequent calls to init()
>> in other EPackages could skip their interdependency initialization.
>> - Again, is this reasonable?
> I'm not sure I follow, but I'd be very reluctant to change a process
> that's proven to be a hot spot for unusual bugs.
>> - Would this approach lead to concurrency problems?
> Without a doubt it would lead to some unanticipated problem...
>>
>> 3. Reduce the number of method-calls per initialization
>> As the EPackageDescriptor accesses the eINSTANCE field within its
>> getEPackage() method via reflection each EPackage initialization
>> requires 10 method calls. This number could be reduced by providing a
>> public getInstance() method for accessing the EPackage instance.
> Again, this is scary code the relies on how classes are loaded lazily by
> the JVM. The stack size doesn't depend on the size of the method, only
> the size of the stack frames which is related to the number of
> variables....
>> - Why was this complicated way of accessing the EPackage instance via
>> the eINSTANCE field chosen?
> You could look through the bugzilla history for the template to see how
> this has evolved based on subtle problems.
>> - Could this be substituted by a getInstance() method or would this
>> introduce concurrency problems?
>>
>> I would really like to better understand the rational behind the
>> design decisions made for the EPackage initialization and would
>> appreciate any feedback on the above proposed solutions and their
>> corresponding questions.
>> Of course if anyone has a better idea on how to solve this
>> StackOverflow problem, it is more than welcome.
>>
>> Thanks and best regards,
>>
>> Paul
> Are you using nested packages? Is that necessary? How are your packages
> separated across GenModels? Do you have three different GenModels?
Re: StackOverflowError on EPackage Initialization [message #522656 is a reply to message #522585] Tue, 23 March 2010 14:03 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33139
Registered: July 2009
Senior Member
Paul,

The problem is the one huge GenModel for your one huge tree of
packages. The nested structure makes all the packages depend on each
other given the interconnected parent/child relations between them and
even then, as you note, the GenModel tries to figure out dependencies
only for packages that cross GenModels, not for packages within the one
GenModel.

Is it really a single huge tree of packages or are there at least a
couple of separate roots? You'll see in the newgroup/forum history that
I've often pointed out that package nesting tends to result in tool
problems that you'd not encounter otherwise. Nesting isn't necessary
because the GenPackage Base Package property helps determine the fully
qualified Java package so a package x and a package y could both have
Base Package set to com.example and com.example.y so product
com.example.x and com.example.x.y, i.e, to produce any type of Java nesting.


Paul Hoser wrote:
> Hi Ed,
>
> thanks for the quick response. Sorry, for using the wrong newsgroup.
>
> My model does contain nested packages. The ecore file I am using is
> not under my control. I am obtaining the ecore file from a
> standardization consortia. I could post-process the ecore file but I
> would actually like to keep the package structure as provided.
>
> But would not having nested packages actually change anything? The
> EpackageImpl.DependencyHelper simply gets all packages from a
> GenModel, if they're nested or not.
>
> public DependencyHelper()
> {
> ...
> interDependencies = new ArrayList<GenPackage>();
> collectPackages(interDependencies,getGenModel().getGenPackag es(),-1);
> interDependencies.remove(GenPackageImpl.this);
> ...
> }
>
>
>
> I am not using different GenModels. My packages are all within one big
> GenModel.
>
>
> Best regards,
>
> Paul
>
> On 22.03.2010 17:45, Ed Merks wrote:
>> Paul,
>>
>> It's best to use the EMF newsgroup/forum, for EMF questions. I've added
>> it to the "to" list of the reply.
>>
>>
>> Paul Hoser wrote:
>>> Hi Everybody!
>>>
>>> I have a problem with my EMF model. I am getting a StackOverflowError
>>> when my EPackages are initialized. My model is rather large. It
>>> consists of about 150 packages each containing at least one classifier.
>>>
>>> Within the init() method of an EPackage the inter-depending EPackages
>>> are initialized recursively. The interdenpendencies of an EPackage are
>>> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
>>> like this:
>>>
>>> public DependencyHelper()
>>> {
>>> ...
>>> interDependencies = new ArrayList<GenPackage>();
>>> collectPackages(interDependencies, getGenModel().getGenPackages(), -1);
>>> interDependencies.remove(GenPackageImpl.this);
>>> ...
>>> }
>>>
>>>
>>>
>>> protected void collectPackages(List<GenPackage> result,
>>> List<GenPackage> genPackages, int depth)
>>> {
>>> if (depth == 0) return;
>>>
>>> for (GenPackage genPackage : genPackages)
>>> {
>>> if (genPackage.hasClassifiers())
>>> {
>>> result.add(genPackage);
>>> collectPackages(result, genPackage.getNestedGenPackages(), depth - 1);
>>> }
>>> else
>>> {
>>> collectPackages(result, genPackage.getNestedGenPackages(), depth);
>>> }
>>> }
>>> }
>>>
>>>
>>> This basically means that all EPackages within the model which contain
>>> classifiers are inter-depedenent to each other. If we had an example
>>> model containing three packages (MyPackage, YourPackage, OurPackage)
>>> we would get generated code like this:
>>>
>>>
>>>
>>> public class MyPackageImpl extends EPackageImpl implements MyPackage
>>> {
>>> ...
>>> public static MyPackage init() {
>>> ...
>>> YourPackageImpl theYourPackage = (YourPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>>> instanceof YourPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>>> YourPackage.eINSTANCE);
>>> OurPackageImpl theOurPackage = (OurPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>>> OurPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>>> OurPackage.eINSTANCE);
>>> ...
>>> }
>>> ...
>>> }
>>>
>>> public class YourPackageImpl extends EPackageImpl implements
>>> YourPackage
>>> {
>>> ...
>>> public static YourPackage init() {
>>> ...
>>> MyPackageImpl theMyPackage = (MyPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>>> MyPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>>> MyPackage.eINSTANCE);
>>> OurPackageImpl theOurPackage = (OurPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>>> OurPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>>> OurPackage.eINSTANCE);
>>> ...
>>> }
>>> ...
>>> }
>>>
>>> public class OurPackageImpl extends EPackageImpl implements OurPackage
>>> {
>>> ...
>>> public static OurPackage init() {
>>> ...
>>> MyPackageImpl theMyPackage = (MyPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>>> MyPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>>> MyPackage.eINSTANCE);
>>> YourPackageImpl theYourPackage = (YourPackageImpl)
>>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>>> instanceof YourPackageImpl ?
>>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>>> YourPackage.eINSTANCE);
>>>
>>> ...
>>> }
>>> ...
>>> }
>>>
>>>
>>> If we would now access any of these EPackages, for instance the
>>> MyPackage, via the eINSTANCE field all three packages would be
>>> initialized recursively and we would get the following stacktrace:
>>>
>>> OurPackageImpl.init() line: 655 OurPackage.<clinit>() line: 75
>>> Unsafe.ensureClassInitialized(Class) line: not available [native
>>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>>> Field.acquireFieldAccessor(boolean) line: 918
>>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>>> EPackageRegistryImpl.getEPackage(String) line: 133
>>> YourPackageImpl.init() line: 698 YourPackage.<clinit>() line: 78
>>> Unsafe.ensureClassInitialized(Class) line: not available [native
>>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>>> Field.acquireFieldAccessor(boolean) line: 918
>>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>>> EPackageRegistryImpl.getEPackage(String) line: 133
>>> MyPackageImpl.init() line: 714 MyPackage.<clinit>() line: 77
>>>
>>> If this is performed not only for three packages (as listed above) but
>>> for 150 the 64K of stack size are not sufficient anymore.
>>>
>>>
>>>
>>> SOLUTION PROPOSALS & QUESTIONS
>>> ------------------------------
>>>
>>> A possible solution would be to simply increase the stack size via the
>>> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
>>> need to support Java 1.5.
>> Surely there must be a way to increase the stack size on all JVMs. That
>> seems like a pretty basic thing.
>>>
>>> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>>>
>>>
>>> I thought of some options for solving this issue. Unfortunately, my
>>> knowledge of EMF internals is too little to decide if these approaches
>>> are reasonable or not.
>>>
>>> 1. Reducing the number of interdependencies
>>> The algorithm for calculating the set of inter-depending EPackages
>>> could be optimized.
>>> - Is this a reasonable approach?
>> Certainly we make assumptions that packages all generated from the same
>> GenModel are interdependent. We could compute that in more detail...
>>> - Or is it necessary to always initialize all EPackages as soon as one
>>> EPackage is initialized?
>> Only if they are mutually dependent.
>>> - What is the interdependency initialization required for?
>> So that the metadata itself can be hooked up properly. Imagine each
>> package with a class with a feature of a type from the other package.
>> You'd need to create each package, each class, and each feature, and
>> then hook up the cross references between them.
>>>
>>> 2. Make the Interdependency Initialization Non-Recursive
>> You need to initialize the things on which you depend before can can
>> initialize. Each package knows it's own dependencies...
>>> It could be possible to set a "inDependencyInitialization" flag which
>>> is set by the first EPackage initialized. Subsequent calls to init()
>>> in other EPackages could skip their interdependency initialization.
>>> - Again, is this reasonable?
>> I'm not sure I follow, but I'd be very reluctant to change a process
>> that's proven to be a hot spot for unusual bugs.
>>> - Would this approach lead to concurrency problems?
>> Without a doubt it would lead to some unanticipated problem...
>>>
>>> 3. Reduce the number of method-calls per initialization
>>> As the EPackageDescriptor accesses the eINSTANCE field within its
>>> getEPackage() method via reflection each EPackage initialization
>>> requires 10 method calls. This number could be reduced by providing a
>>> public getInstance() method for accessing the EPackage instance.
>> Again, this is scary code the relies on how classes are loaded lazily by
>> the JVM. The stack size doesn't depend on the size of the method, only
>> the size of the stack frames which is related to the number of
>> variables....
>>> - Why was this complicated way of accessing the EPackage instance via
>>> the eINSTANCE field chosen?
>> You could look through the bugzilla history for the template to see how
>> this has evolved based on subtle problems.
>>> - Could this be substituted by a getInstance() method or would this
>>> introduce concurrency problems?
>>>
>>> I would really like to better understand the rational behind the
>>> design decisions made for the EPackage initialization and would
>>> appreciate any feedback on the above proposed solutions and their
>>> corresponding questions.
>>> Of course if anyone has a better idea on how to solve this
>>> StackOverflow problem, it is more than welcome.
>>>
>>> Thanks and best regards,
>>>
>>> Paul
>> Are you using nested packages? Is that necessary? How are your packages
>> separated across GenModels? Do you have three different GenModels?
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: StackOverflowError on EPackage Initialization [message #525315 is a reply to message #522656] Tue, 06 April 2010 04:10 Go to previous message
Paul Hoser is currently offline Paul HoserFriend
Messages: 4
Registered: March 2010
Junior Member
Hi Ed,

thanks for the help.

Until now I only tried to split up my model by grouping packages in
different genmodels but I failed. This is due to too many
interdependencies between the packages in my model which would introduce
cyclic dependencies between the genmodels.

I'll try your second solution and will try to flatten the package
structure of my model and use the Base Package attribute.

Thanks a lot again for your help!

Best regards,

Paul

On 23.03.2010 15:03, Ed Merks wrote:
> Paul,
>
> The problem is the one huge GenModel for your one huge tree of packages.
> The nested structure makes all the packages depend on each other given
> the interconnected parent/child relations between them and even then, as
> you note, the GenModel tries to figure out dependencies only for
> packages that cross GenModels, not for packages within the one GenModel.
> Is it really a single huge tree of packages or are there at least a
> couple of separate roots? You'll see in the newgroup/forum history that
> I've often pointed out that package nesting tends to result in tool
> problems that you'd not encounter otherwise. Nesting isn't necessary
> because the GenPackage Base Package property helps determine the fully
> qualified Java package so a package x and a package y could both have
> Base Package set to com.example and com.example.y so product
> com.example.x and com.example.x.y, i.e, to produce any type of Java
> nesting.
>
>
> Paul Hoser wrote:
>> Hi Ed,
>>
>> thanks for the quick response. Sorry, for using the wrong newsgroup.
>>
>> My model does contain nested packages. The ecore file I am using is
>> not under my control. I am obtaining the ecore file from a
>> standardization consortia. I could post-process the ecore file but I
>> would actually like to keep the package structure as provided.
>>
>> But would not having nested packages actually change anything? The
>> EpackageImpl.DependencyHelper simply gets all packages from a
>> GenModel, if they're nested or not.
>>
>> public DependencyHelper()
>> {
>> ...
>> interDependencies = new ArrayList<GenPackage>();
>> collectPackages(interDependencies,getGenModel().getGenPackag es(),-1);
>> interDependencies.remove(GenPackageImpl.this);
>> ...
>> }
>>
>>
>>
>> I am not using different GenModels. My packages are all within one big
>> GenModel.
>>
>>
>> Best regards,
>>
>> Paul
>>
>> On 22.03.2010 17:45, Ed Merks wrote:
>>> Paul,
>>>
>>> It's best to use the EMF newsgroup/forum, for EMF questions. I've added
>>> it to the "to" list of the reply.
>>>
>>>
>>> Paul Hoser wrote:
>>>> Hi Everybody!
>>>>
>>>> I have a problem with my EMF model. I am getting a StackOverflowError
>>>> when my EPackages are initialized. My model is rather large. It
>>>> consists of about 150 packages each containing at least one classifier.
>>>>
>>>> Within the init() method of an EPackage the inter-depending EPackages
>>>> are initialized recursively. The interdenpendencies of an EPackage are
>>>> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
>>>> like this:
>>>>
>>>> public DependencyHelper()
>>>> {
>>>> ...
>>>> interDependencies = new ArrayList<GenPackage>();
>>>> collectPackages(interDependencies, getGenModel().getGenPackages(), -1);
>>>> interDependencies.remove(GenPackageImpl.this);
>>>> ...
>>>> }
>>>>
>>>>
>>>>
>>>> protected void collectPackages(List<GenPackage> result,
>>>> List<GenPackage> genPackages, int depth)
>>>> {
>>>> if (depth == 0) return;
>>>>
>>>> for (GenPackage genPackage : genPackages)
>>>> {
>>>> if (genPackage.hasClassifiers())
>>>> {
>>>> result.add(genPackage);
>>>> collectPackages(result, genPackage.getNestedGenPackages(), depth - 1);
>>>> }
>>>> else
>>>> {
>>>> collectPackages(result, genPackage.getNestedGenPackages(), depth);
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>> This basically means that all EPackages within the model which contain
>>>> classifiers are inter-depedenent to each other. If we had an example
>>>> model containing three packages (MyPackage, YourPackage, OurPackage)
>>>> we would get generated code like this:
>>>>
>>>>
>>>>
>>>> public class MyPackageImpl extends EPackageImpl implements MyPackage
>>>> {
>>>> ...
>>>> public static MyPackage init() {
>>>> ...
>>>> YourPackageImpl theYourPackage = (YourPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>>>> instanceof YourPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>>>> YourPackage.eINSTANCE);
>>>> OurPackageImpl theOurPackage = (OurPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>>>> OurPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>>>> OurPackage.eINSTANCE);
>>>> ...
>>>> }
>>>> ...
>>>> }
>>>>
>>>> public class YourPackageImpl extends EPackageImpl implements
>>>> YourPackage
>>>> {
>>>> ...
>>>> public static YourPackage init() {
>>>> ...
>>>> MyPackageImpl theMyPackage = (MyPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>>>> MyPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>>>> MyPackage.eINSTANCE);
>>>> OurPackageImpl theOurPackage = (OurPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
>>>> OurPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
>>>> OurPackage.eINSTANCE);
>>>> ...
>>>> }
>>>> ...
>>>> }
>>>>
>>>> public class OurPackageImpl extends EPackageImpl implements OurPackage
>>>> {
>>>> ...
>>>> public static OurPackage init() {
>>>> ...
>>>> MyPackageImpl theMyPackage = (MyPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
>>>> MyPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
>>>> MyPackage.eINSTANCE);
>>>> YourPackageImpl theYourPackage = (YourPackageImpl)
>>>> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
>>>> instanceof YourPackageImpl ?
>>>> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
>>>> YourPackage.eINSTANCE);
>>>>
>>>> ...
>>>> }
>>>> ...
>>>> }
>>>>
>>>>
>>>> If we would now access any of these EPackages, for instance the
>>>> MyPackage, via the eINSTANCE field all three packages would be
>>>> initialized recursively and we would get the following stacktrace:
>>>>
>>>> OurPackageImpl.init() line: 655 OurPackage.<clinit>() line: 75
>>>> Unsafe.ensureClassInitialized(Class) line: not available [native
>>>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>>>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>>>> Field.acquireFieldAccessor(boolean) line: 918
>>>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>>>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>>>> EPackageRegistryImpl.getEPackage(String) line: 133
>>>> YourPackageImpl.init() line: 698 YourPackage.<clinit>() line: 78
>>>> Unsafe.ensureClassInitialized(Class) line: not available [native
>>>> method] UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean)
>>>> line: 25 ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
>>>> Field.acquireFieldAccessor(boolean) line: 918
>>>> Field.getFieldAccessor(Object) line: 899 Field.get(Object) line: 358
>>>> RegistryReader$EPackageDescriptor.getEPackage() line: 274
>>>> EPackageRegistryImpl.getEPackage(String) line: 133
>>>> MyPackageImpl.init() line: 714 MyPackage.<clinit>() line: 77
>>>>
>>>> If this is performed not only for three packages (as listed above) but
>>>> for 150 the 64K of stack size are not sufficient anymore.
>>>>
>>>>
>>>>
>>>> SOLUTION PROPOSALS & QUESTIONS
>>>> ------------------------------
>>>>
>>>> A possible solution would be to simply increase the stack size via the
>>>> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
>>>> need to support Java 1.5.
>>> Surely there must be a way to increase the stack size on all JVMs. That
>>> seems like a pretty basic thing.
>>>>
>>>> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>>>>
>>>>
>>>> I thought of some options for solving this issue. Unfortunately, my
>>>> knowledge of EMF internals is too little to decide if these approaches
>>>> are reasonable or not.
>>>>
>>>> 1. Reducing the number of interdependencies
>>>> The algorithm for calculating the set of inter-depending EPackages
>>>> could be optimized.
>>>> - Is this a reasonable approach?
>>> Certainly we make assumptions that packages all generated from the same
>>> GenModel are interdependent. We could compute that in more detail...
>>>> - Or is it necessary to always initialize all EPackages as soon as one
>>>> EPackage is initialized?
>>> Only if they are mutually dependent.
>>>> - What is the interdependency initialization required for?
>>> So that the metadata itself can be hooked up properly. Imagine each
>>> package with a class with a feature of a type from the other package.
>>> You'd need to create each package, each class, and each feature, and
>>> then hook up the cross references between them.
>>>>
>>>> 2. Make the Interdependency Initialization Non-Recursive
>>> You need to initialize the things on which you depend before can can
>>> initialize. Each package knows it's own dependencies...
>>>> It could be possible to set a "inDependencyInitialization" flag which
>>>> is set by the first EPackage initialized. Subsequent calls to init()
>>>> in other EPackages could skip their interdependency initialization.
>>>> - Again, is this reasonable?
>>> I'm not sure I follow, but I'd be very reluctant to change a process
>>> that's proven to be a hot spot for unusual bugs.
>>>> - Would this approach lead to concurrency problems?
>>> Without a doubt it would lead to some unanticipated problem...
>>>>
>>>> 3. Reduce the number of method-calls per initialization
>>>> As the EPackageDescriptor accesses the eINSTANCE field within its
>>>> getEPackage() method via reflection each EPackage initialization
>>>> requires 10 method calls. This number could be reduced by providing a
>>>> public getInstance() method for accessing the EPackage instance.
>>> Again, this is scary code the relies on how classes are loaded lazily by
>>> the JVM. The stack size doesn't depend on the size of the method, only
>>> the size of the stack frames which is related to the number of
>>> variables....
>>>> - Why was this complicated way of accessing the EPackage instance via
>>>> the eINSTANCE field chosen?
>>> You could look through the bugzilla history for the template to see how
>>> this has evolved based on subtle problems.
>>>> - Could this be substituted by a getInstance() method or would this
>>>> introduce concurrency problems?
>>>>
>>>> I would really like to better understand the rational behind the
>>>> design decisions made for the EPackage initialization and would
>>>> appreciate any feedback on the above proposed solutions and their
>>>> corresponding questions.
>>>> Of course if anyone has a better idea on how to solve this
>>>> StackOverflow problem, it is more than welcome.
>>>>
>>>> Thanks and best regards,
>>>>
>>>> Paul
>>> Are you using nested packages? Is that necessary? How are your packages
>>> separated across GenModels? Do you have three different GenModels?
>>
Previous Topic:Validating conformance of serialized resources to their metamodel
Next Topic:teneo hibernate LazyInitializationException
Goto Forum:
  


Current Time: Tue Apr 23 06:55:08 GMT 2024

Powered by FUDForum. Page generated in 0.03283 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top