Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » StackOverflowError with EContentAdapter
StackOverflowError with EContentAdapter [message #1384812] Mon, 02 June 2014 09:19 Go to next message
Knut Wannheden is currently offline Knut WannhedenFriend
Messages: 296
Registered: July 2009
Senior Member
Hi all,

I have run into a StackOverflowError problem when attaching
EContentAdapters to deep EMF models (more than 1000 levels deeps). You
can see the recursion in this stack trace:

at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
at
org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
at
org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
at
org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
at
org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)

I have tried to increase the stack size using -Xss and that does help,
but I have to increase it quite a bit (multiple MiB, depending on model
depth) to handle deep models and with Eclipse having quite a few threads
running, that would end up using a lot of memory.

I was a bit surprised to see that I could execute the same piece of code
multiple times and that it would sometimes throw a StackOverflowError
and sometimes not. It could for instance happen that it works fine the
first time, fails the second time, and works fine again the third time.
But after running the same code multiple times (e.g. 10) it would either
consistently fail or consistently succeed. I suspect that the JIT (and
HotSpot) code is using the same stack and that this explains why it
seems to be unpredictable.

While I don't see anything EMF could do differently here, I was
wondering if other people have run into the same problem and how they
dealt with it.

I am currently considering running some code during startup of the tool
which would trigger the JIT for the involved code and would then make
StackOverflowErrors less probable to occur.

Here is a simple JUnit test I have been using to do my testing:

public class StackOverflowTest {

@Test
public void testStackOverflow() {
test(20000, 1); // OK
// test(1315, 0); // NOK
// test(1315, 1); // OK
}

private void test(final int depth, final int warmupReps) {
for (int i = 0; i < warmupReps; i++) {
try {
deepModel(depth);
} catch (StackOverflowError e) {}
}
deepModel(depth);
}

private Resource deepModel(final int depth) {
Resource r = new
ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
r.getContents().add(pkg);
for (int i = 0; i < depth; i++) {
EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
pkg.getESubpackages().add(nested);
pkg = nested;
}
new EContentAdapter().setTarget(r);
return r;
}

}

Regards,

--knut
Re: StackOverflowError with EContentAdapter [message #1384872 is a reply to message #1384812] Mon, 02 June 2014 16:42 Go to previous messageGo to next message
Hallvard Traetteberg is currently offline Hallvard TraettebergFriend
Messages: 601
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

I guess the problem occurs since you attach the adapter to the top and
it recursively attaches it to all levels below. Perhaps it is possible
to attach it bottom-up instead, i.e. to the children before the parent?
Hopefully, you can make it notice that it already is attached to the
children and stop it from recursing.

Hallvard

On 02.06.14 11:19, Knut Wannheden wrote:
> Hi all,
>
> I have run into a StackOverflowError problem when attaching
> EContentAdapters to deep EMF models (more than 1000 levels deeps). You
> can see the recursion in this stack trace:
>
> at
> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>
> at
> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>
> at
> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>
> at
> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
> at
> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>
> at
> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>
> at
> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>
> at
> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>
> at
> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>
> at
> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>
> at
> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
> at
> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>
> at
> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>
> at
> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>
>
> I have tried to increase the stack size using -Xss and that does help,
> but I have to increase it quite a bit (multiple MiB, depending on model
> depth) to handle deep models and with Eclipse having quite a few threads
> running, that would end up using a lot of memory.
>
> I was a bit surprised to see that I could execute the same piece of code
> multiple times and that it would sometimes throw a StackOverflowError
> and sometimes not. It could for instance happen that it works fine the
> first time, fails the second time, and works fine again the third time.
> But after running the same code multiple times (e.g. 10) it would either
> consistently fail or consistently succeed. I suspect that the JIT (and
> HotSpot) code is using the same stack and that this explains why it
> seems to be unpredictable.
>
> While I don't see anything EMF could do differently here, I was
> wondering if other people have run into the same problem and how they
> dealt with it.
>
> I am currently considering running some code during startup of the tool
> which would trigger the JIT for the involved code and would then make
> StackOverflowErrors less probable to occur.
>
> Here is a simple JUnit test I have been using to do my testing:
>
> public class StackOverflowTest {
>
> @Test
> public void testStackOverflow() {
> test(20000, 1); // OK
> // test(1315, 0); // NOK
> // test(1315, 1); // OK
> }
>
> private void test(final int depth, final int warmupReps) {
> for (int i = 0; i < warmupReps; i++) {
> try {
> deepModel(depth);
> } catch (StackOverflowError e) {}
> }
> deepModel(depth);
> }
>
> private Resource deepModel(final int depth) {
> Resource r = new
> ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
> EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
> r.getContents().add(pkg);
> for (int i = 0; i < depth; i++) {
> EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
> pkg.getESubpackages().add(nested);
> pkg = nested;
> }
> new EContentAdapter().setTarget(r);
> return r;
> }
>
> }
>
> Regards,
>
> --knut
Re: StackOverflowError with EContentAdapter [message #1384873 is a reply to message #1384872] Mon, 02 June 2014 17:05 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 26237
Registered: July 2009
Senior Member
Hallvard,

Of course the obvious approach for doing that would also involve
recursion... A tree iterator at least allows one to visit all objects
without recursion; internally it uses a stack, but that stack is in the
heap. I suppose if you kept track of the depth of each node visited in
such an iteration and added the adapter to the deepest nodes first,
you'd avoid a stack overflow, though it would be a lot less efficient.


On 02/06/2014 6:42 PM, Hallvard Trætteberg wrote:
> Hi,
>
> I guess the problem occurs since you attach the adapter to the top and
> it recursively attaches it to all levels below. Perhaps it is possible
> to attach it bottom-up instead, i.e. to the children before the
> parent? Hopefully, you can make it notice that it already is attached
> to the children and stop it from recursing.
>
> Hallvard
>
> On 02.06.14 11:19, Knut Wannheden wrote:
>> Hi all,
>>
>> I have run into a StackOverflowError problem when attaching
>> EContentAdapters to deep EMF models (more than 1000 levels deeps). You
>> can see the recursion in this stack trace:
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>
>>
>> at
>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>
>>
>> at
>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>
>>
>> at
>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>
>>
>> at
>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>
>>
>>
>> I have tried to increase the stack size using -Xss and that does help,
>> but I have to increase it quite a bit (multiple MiB, depending on model
>> depth) to handle deep models and with Eclipse having quite a few threads
>> running, that would end up using a lot of memory.
>>
>> I was a bit surprised to see that I could execute the same piece of code
>> multiple times and that it would sometimes throw a StackOverflowError
>> and sometimes not. It could for instance happen that it works fine the
>> first time, fails the second time, and works fine again the third time.
>> But after running the same code multiple times (e.g. 10) it would either
>> consistently fail or consistently succeed. I suspect that the JIT (and
>> HotSpot) code is using the same stack and that this explains why it
>> seems to be unpredictable.
>>
>> While I don't see anything EMF could do differently here, I was
>> wondering if other people have run into the same problem and how they
>> dealt with it.
>>
>> I am currently considering running some code during startup of the tool
>> which would trigger the JIT for the involved code and would then make
>> StackOverflowErrors less probable to occur.
>>
>> Here is a simple JUnit test I have been using to do my testing:
>>
>> public class StackOverflowTest {
>>
>> @Test
>> public void testStackOverflow() {
>> test(20000, 1); // OK
>> // test(1315, 0); // NOK
>> // test(1315, 1); // OK
>> }
>>
>> private void test(final int depth, final int warmupReps) {
>> for (int i = 0; i < warmupReps; i++) {
>> try {
>> deepModel(depth);
>> } catch (StackOverflowError e) {}
>> }
>> deepModel(depth);
>> }
>>
>> private Resource deepModel(final int depth) {
>> Resource r = new
>> ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
>> EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
>> r.getContents().add(pkg);
>> for (int i = 0; i < depth; i++) {
>> EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
>> pkg.getESubpackages().add(nested);
>> pkg = nested;
>> }
>> new EContentAdapter().setTarget(r);
>> return r;
>> }
>>
>> }
>>
>> Regards,
>>
>> --knut
>
Re: StackOverflowError with EContentAdapter [message #1384877 is a reply to message #1384873] Mon, 02 June 2014 17:44 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 4154
Registered: July 2009
Senior Member
Hi

Yes/No.

If you can guarantee to create all nodes before you set the
EContentAdapter on the Resource you can do

new EContentAdapter() {
@Override
protected void setTarget(EObject target) {
basicSetTarget(target);
}

@Override
protected void setTarget(Resource target) {
basicSetTarget(target);
for (TreeIterator<EObject> tit = target.getAllContents();
tit.hasNext(); )
{
EObject eObject = tit.next();
addAdapter(eObject);
}
}
}.setTarget(r);

If you have late addition of nodes you'll have to make setTarget(EObject
target) check to guard a similar recursion with a check to see if it
already has an EContentAdapter.

Regards

Ed Willink

On 02/06/2014 18:05, Ed Merks wrote:
> Hallvard,
>
> Of course the obvious approach for doing that would also involve
> recursion... A tree iterator at least allows one to visit all objects
> without recursion; internally it uses a stack, but that stack is in
> the heap. I suppose if you kept track of the depth of each node
> visited in such an iteration and added the adapter to the deepest
> nodes first, you'd avoid a stack overflow, though it would be a lot
> less efficient.
>
>
> On 02/06/2014 6:42 PM, Hallvard Trætteberg wrote:
>> Hi,
>>
>> I guess the problem occurs since you attach the adapter to the top
>> and it recursively attaches it to all levels below. Perhaps it is
>> possible to attach it bottom-up instead, i.e. to the children before
>> the parent? Hopefully, you can make it notice that it already is
>> attached to the children and stop it from recursing.
>>
>> Hallvard
>>
>> On 02.06.14 11:19, Knut Wannheden wrote:
>>> Hi all,
>>>
>>> I have run into a StackOverflowError problem when attaching
>>> EContentAdapters to deep EMF models (more than 1000 levels deeps). You
>>> can see the recursion in this stack trace:
>>>
>>> at
>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>>
>>>
>>> at
>>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>>
>>>
>>> at
>>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>>
>>>
>>> at
>>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>>
>>>
>>> at
>>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>>
>>>
>>> at
>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>>
>>>
>>>
>>> I have tried to increase the stack size using -Xss and that does help,
>>> but I have to increase it quite a bit (multiple MiB, depending on model
>>> depth) to handle deep models and with Eclipse having quite a few
>>> threads
>>> running, that would end up using a lot of memory.
>>>
>>> I was a bit surprised to see that I could execute the same piece of
>>> code
>>> multiple times and that it would sometimes throw a StackOverflowError
>>> and sometimes not. It could for instance happen that it works fine the
>>> first time, fails the second time, and works fine again the third time.
>>> But after running the same code multiple times (e.g. 10) it would
>>> either
>>> consistently fail or consistently succeed. I suspect that the JIT (and
>>> HotSpot) code is using the same stack and that this explains why it
>>> seems to be unpredictable.
>>>
>>> While I don't see anything EMF could do differently here, I was
>>> wondering if other people have run into the same problem and how they
>>> dealt with it.
>>>
>>> I am currently considering running some code during startup of the tool
>>> which would trigger the JIT for the involved code and would then make
>>> StackOverflowErrors less probable to occur.
>>>
>>> Here is a simple JUnit test I have been using to do my testing:
>>>
>>> public class StackOverflowTest {
>>>
>>> @Test
>>> public void testStackOverflow() {
>>> test(20000, 1); // OK
>>> // test(1315, 0); // NOK
>>> // test(1315, 1); // OK
>>> }
>>>
>>> private void test(final int depth, final int warmupReps) {
>>> for (int i = 0; i < warmupReps; i++) {
>>> try {
>>> deepModel(depth);
>>> } catch (StackOverflowError e) {}
>>> }
>>> deepModel(depth);
>>> }
>>>
>>> private Resource deepModel(final int depth) {
>>> Resource r = new
>>> ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
>>> EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
>>> r.getContents().add(pkg);
>>> for (int i = 0; i < depth; i++) {
>>> EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
>>> pkg.getESubpackages().add(nested);
>>> pkg = nested;
>>> }
>>> new EContentAdapter().setTarget(r);
>>> return r;
>>> }
>>>
>>> }
>>>
>>> Regards,
>>>
>>> --knut
>>
>
Re: StackOverflowError with EContentAdapter [message #1385033 is a reply to message #1384812] Tue, 03 June 2014 19:50 Go to previous messageGo to next message
Erdal Karaca is currently offline Erdal KaracaFriend
Messages: 756
Registered: July 2009
Senior Member
Do your algorithms/data structures really need a depth level of 1000? Or are you experimenting with EMF (in a 'toy project')?

Knut Wannheden wrote on Mon, 02 June 2014 11:19
Hi all,

I have run into a StackOverflowError problem when attaching
EContentAdapters to deep EMF models (more than 1000 levels deeps). You
can see the recursion in this stack trace:

at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
at
org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
at
org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
at
org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
at
org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
at
org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
at
org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)

I have tried to increase the stack size using -Xss and that does help,
but I have to increase it quite a bit (multiple MiB, depending on model
depth) to handle deep models and with Eclipse having quite a few threads
running, that would end up using a lot of memory.

I was a bit surprised to see that I could execute the same piece of code
multiple times and that it would sometimes throw a StackOverflowError
and sometimes not. It could for instance happen that it works fine the
first time, fails the second time, and works fine again the third time.
But after running the same code multiple times (e.g. 10) it would either
consistently fail or consistently succeed. I suspect that the JIT (and
HotSpot) code is using the same stack and that this explains why it
seems to be unpredictable.

While I don't see anything EMF could do differently here, I was
wondering if other people have run into the same problem and how they
dealt with it.

I am currently considering running some code during startup of the tool
which would trigger the JIT for the involved code and would then make
StackOverflowErrors less probable to occur.

Here is a simple JUnit test I have been using to do my testing:

public class StackOverflowTest {

@Test
public void testStackOverflow() {
test(20000, 1); // OK
// test(1315, 0); // NOK
// test(1315, 1); // OK
}

private void test(final int depth, final int warmupReps) {
for (int i = 0; i < warmupReps; i++) {
try {
deepModel(depth);
} catch (StackOverflowError e) {}
}
deepModel(depth);
}

private Resource deepModel(final int depth) {
Resource r = new
ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
r.getContents().add(pkg);
for (int i = 0; i < depth; i++) {
EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
pkg.getESubpackages().add(nested);
pkg = nested;
}
new EContentAdapter().setTarget(r);
return r;
}

}

Regards,

--knut

Re: StackOverflowError with EContentAdapter [message #1385035 is a reply to message #1384877] Tue, 03 June 2014 19:55 Go to previous messageGo to next message
Knut Wannheden is currently offline Knut WannhedenFriend
Messages: 296
Registered: July 2009
Senior Member
Hi all,

Thank you all for the input and ideas!

Unfortunately it is not quite as simple as I outlined (also apart from
the fact that my model isn't a long chain of nested EPackages :-)). I
use third party libraries and frameworks (e.g. Xtext) which install
their own EContentAdapters (e.g. Xtext's OnChangeEvictingCache). These
could be hard to customize in some cases, but performance is also a very
important aspect in the application, so I would also have to test how
much worse the proposed solutions perform.

I was simply hoping that someone else had stumbled across the same
problem in the past and had come up with some great solution. "Priming"
the JIT is the best thing I have come up with so far.

Regards,

--knut

On 02/06/14 19:44, Ed Willink wrote:
> Hi
>
> Yes/No.
>
> If you can guarantee to create all nodes before you set the
> EContentAdapter on the Resource you can do
>
> new EContentAdapter() {
> @Override
> protected void setTarget(EObject target) {
> basicSetTarget(target);
> }
>
> @Override
> protected void setTarget(Resource target) {
> basicSetTarget(target);
> for (TreeIterator<EObject> tit = target.getAllContents(); tit.hasNext(); )
> {
> EObject eObject = tit.next();
> addAdapter(eObject);
> }
> }
> }.setTarget(r);
>
> If you have late addition of nodes you'll have to make setTarget(EObject
> target) check to guard a similar recursion with a check to see if it
> already has an EContentAdapter.
>
> Regards
>
> Ed Willink
>
> On 02/06/2014 18:05, Ed Merks wrote:
>> Hallvard,
>>
>> Of course the obvious approach for doing that would also involve
>> recursion... A tree iterator at least allows one to visit all objects
>> without recursion; internally it uses a stack, but that stack is in
>> the heap. I suppose if you kept track of the depth of each node
>> visited in such an iteration and added the adapter to the deepest
>> nodes first, you'd avoid a stack overflow, though it would be a lot
>> less efficient.
>>
>>
>> On 02/06/2014 6:42 PM, Hallvard Trætteberg wrote:
>>> Hi,
>>>
>>> I guess the problem occurs since you attach the adapter to the top
>>> and it recursively attaches it to all levels below. Perhaps it is
>>> possible to attach it bottom-up instead, i.e. to the children before
>>> the parent? Hopefully, you can make it notice that it already is
>>> attached to the children and stop it from recursing.
>>>
>>> Hallvard
>>>
>>> On 02.06.14 11:19, Knut Wannheden wrote:
>>>> Hi all,
>>>>
>>>> I have run into a StackOverflowError problem when attaching
>>>> EContentAdapters to deep EMF models (more than 1000 levels deeps). You
>>>> can see the recursion in this stack trace:
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>>>
>>>>
>>>> at
>>>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>>>
>>>>
>>>>
>>>> I have tried to increase the stack size using -Xss and that does help,
>>>> but I have to increase it quite a bit (multiple MiB, depending on model
>>>> depth) to handle deep models and with Eclipse having quite a few
>>>> threads
>>>> running, that would end up using a lot of memory.
>>>>
>>>> I was a bit surprised to see that I could execute the same piece of
>>>> code
>>>> multiple times and that it would sometimes throw a StackOverflowError
>>>> and sometimes not. It could for instance happen that it works fine the
>>>> first time, fails the second time, and works fine again the third time.
>>>> But after running the same code multiple times (e.g. 10) it would
>>>> either
>>>> consistently fail or consistently succeed. I suspect that the JIT (and
>>>> HotSpot) code is using the same stack and that this explains why it
>>>> seems to be unpredictable.
>>>>
>>>> While I don't see anything EMF could do differently here, I was
>>>> wondering if other people have run into the same problem and how they
>>>> dealt with it.
>>>>
>>>> I am currently considering running some code during startup of the tool
>>>> which would trigger the JIT for the involved code and would then make
>>>> StackOverflowErrors less probable to occur.
>>>>
>>>> Here is a simple JUnit test I have been using to do my testing:
>>>>
>>>> public class StackOverflowTest {
>>>>
>>>> @Test
>>>> public void testStackOverflow() {
>>>> test(20000, 1); // OK
>>>> // test(1315, 0); // NOK
>>>> // test(1315, 1); // OK
>>>> }
>>>>
>>>> private void test(final int depth, final int warmupReps) {
>>>> for (int i = 0; i < warmupReps; i++) {
>>>> try {
>>>> deepModel(depth);
>>>> } catch (StackOverflowError e) {}
>>>> }
>>>> deepModel(depth);
>>>> }
>>>>
>>>> private Resource deepModel(final int depth) {
>>>> Resource r = new
>>>> ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
>>>> EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
>>>> r.getContents().add(pkg);
>>>> for (int i = 0; i < depth; i++) {
>>>> EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
>>>> pkg.getESubpackages().add(nested);
>>>> pkg = nested;
>>>> }
>>>> new EContentAdapter().setTarget(r);
>>>> return r;
>>>> }
>>>>
>>>> }
>>>>
>>>> Regards,
>>>>
>>>> --knut
>>>
>>
>
Re: StackOverflowError with EContentAdapter [message #1385036 is a reply to message #1385033] Tue, 03 June 2014 20:08 Go to previous messageGo to next message
Knut Wannheden is currently offline Knut WannhedenFriend
Messages: 296
Registered: July 2009
Senior Member
Hi Erdal,

That is a good question. You may find it hard to believe, but one model
I have to deal with has a depth of over 3000 elements! And what may even
sound stranger this is a model produced by an Xtext parser when loading
a particular hand-written source file. The source file conforms to the
grammar of some GPL and contains an expression using almost 3000 string
concatenation operators like this:

"a " + var1 + " b " + var2 + ...

Of course it would be possible to break this expression up into multiple
separate expressions. But the problem I have is that I run into the
StackOverflowError when loading this particular source file in the Xtext
editor...

If the StackOverflowError can't be avoided in some elegant and
transparent way, I will have to find a way to detect this problem and
report it to the user, while still allowing him to edit the source file
in the editor. This may prove a bit tricky.

Regards,

--knut

On 03/06/14 21:50, Erdal Karaca wrote:
> Do your algorithms/data structures really need a depth level of 1000? Or
> are you experimenting with EMF (in a 'toy project')?
>
> Knut Wannheden wrote on Mon, 02 June 2014 11:19
>> Hi all,
>>
>> I have run into a StackOverflowError problem when attaching
>> EContentAdapters to deep EMF models (more than 1000 levels deeps). You
>> can see the recursion in this stack trace:
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>
>> at
>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>
>> at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:489)
>>
>> at
>> org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1ArrayDelegatingAdapterList.didAdd(MinimalEObjectImpl.java:1)
>>
>> at
>> org.eclipse.emf.common.util.ArrayDelegatingEList.addUnique(ArrayDelegatingEList.java:389)
>>
>> at org.eclipse.emf.common.util.AbstractEList.add(AbstractEList.java:301)
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.addAdapter(EContentAdapter.java:349)
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:219)
>>
>> at
>> org.eclipse.emf.ecore.util.EContentAdapter.setTarget(EContentAdapter.java:182)
>>
>>
>> I have tried to increase the stack size using -Xss and that does help,
>> but I have to increase it quite a bit (multiple MiB, depending on
>> model depth) to handle deep models and with Eclipse having quite a few
>> threads running, that would end up using a lot of memory.
>>
>> I was a bit surprised to see that I could execute the same piece of
>> code multiple times and that it would sometimes throw a
>> StackOverflowError and sometimes not. It could for instance happen
>> that it works fine the first time, fails the second time, and works
>> fine again the third time. But after running the same code multiple
>> times (e.g. 10) it would either consistently fail or consistently
>> succeed. I suspect that the JIT (and HotSpot) code is using the same
>> stack and that this explains why it seems to be unpredictable.
>>
>> While I don't see anything EMF could do differently here, I was
>> wondering if other people have run into the same problem and how they
>> dealt with it.
>>
>> I am currently considering running some code during startup of the
>> tool which would trigger the JIT for the involved code and would then
>> make StackOverflowErrors less probable to occur.
>>
>> Here is a simple JUnit test I have been using to do my testing:
>>
>> public class StackOverflowTest {
>>
>> @Test
>> public void testStackOverflow() {
>> test(20000, 1); // OK
>> // test(1315, 0); // NOK
>> // test(1315, 1); // OK
>> }
>>
>> private void test(final int depth, final int warmupReps) {
>> for (int i = 0; i < warmupReps; i++) {
>> try {
>> deepModel(depth);
>> } catch (StackOverflowError e) {}
>> }
>> deepModel(depth);
>> }
>>
>> private Resource deepModel(final int depth) {
>> Resource r = new
>> ResourceFactoryImpl().createResource(URI.createURI("foo:/bar"));
>> EPackage pkg = EcoreFactory.eINSTANCE.createEPackage();
>> r.getContents().add(pkg);
>> for (int i = 0; i < depth; i++) {
>> EPackage nested = EcoreFactory.eINSTANCE.createEPackage();
>> pkg.getESubpackages().add(nested);
>> pkg = nested;
>> }
>> new EContentAdapter().setTarget(r);
>> return r;
>> }
>>
>> }
>>
>> Regards,
>>
>> --knut
>
>
Re: StackOverflowError with EContentAdapter [message #1385037 is a reply to message #1385036] Tue, 03 June 2014 20:26 Go to previous message
Erdal Karaca is currently offline Erdal KaracaFriend
Messages: 756
Registered: July 2009
Senior Member
It is really hard to imagine a grammar with rules needing depth levels of 1000.
Maybe, the "string concatenation operation" of xtext is implemented like this:

concat("a ", concat(var1, concat(" b ", concat(var2, ...)))

which would need that "complex depth level" but should be "optimizable"...

Just ask on the xtext forum.

Knut Wannheden wrote on Tue, 03 June 2014 22:08
Hi Erdal,

That is a good question. You may find it hard to believe, but one model
I have to deal with has a depth of over 3000 elements! And what may even
sound stranger this is a model produced by an Xtext parser when loading
a particular hand-written source file. The source file conforms to the
grammar of some GPL and contains an expression using almost 3000 string
concatenation operators like this:

"a " + var1 + " b " + var2 + ...

Of course it would be possible to break this expression up into multiple
separate expressions. But the problem I have is that I run into the
StackOverflowError when loading this particular source file in the Xtext
editor...

If the StackOverflowError can't be avoided in some elegant and
transparent way, I will have to find a way to detect this problem and
report it to the user, while still allowing him to edit the source file
in the editor. This may prove a bit tricky.

Regards,

--knut

>

Previous Topic:How does EcoreUtil.delete() handles objects that are keys in a EMap?
Next Topic:Casting Object to EObject
Goto Forum:
  


Current Time: Fri Nov 28 15:01:13 GMT 2014

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

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