When Oolite gets the command to create a ship, but the shipdata says no (because of the conditions) Oolite freezes and starts to consume a lot of memory in steps 10MB-40MB until the application gets killed.
You can test it by giving the Adder in Oolites shipdata:
When Oolite gets the command to create a ship, but the shipdata says no (because of the conditions) Oolite freezes and starts to consume a lot of memory in steps 10MB-40MB until the application gets killed.
Not on my mac. But this could be related to the crashes with the astomine from commies.oxp That one also uses conditions for all its ships.
And also Trident-Down uses conditions in shipdata. (And ups-courier also uses conditions for some ships)
When Oolite gets the command to create a ship, but the shipdata says no (because of the conditions) Oolite freezes and starts to consume a lot of memory in steps 10MB-40MB until the application gets killed.
Oh great, another one of those...
*sigh* Confirmed.
There are few problems in universe.m and probabilitySet.
First method count for pset was used in nsarray not MutableProbabilitySet
returnig incorrect value, and other thing is method removeObject
from ConcreteMutableProbabilitySet never removed object
as condition was if(object != nil)return.
So, if there was not ship which satisfied condition
and random is called that would produce endless loop.
int i = 0;
while ([pset countPS] > 0 && i<1000)
{
++i;
// Select a ship, check conditions and return it if possible.
//shipKey = [registry randomShipKeyForRole:role];
shipKey = [pset randomObject]; // this is correct I think
OOLog(@"bane",@"%@ %d",shipKey,[pset countPS]);
if ([self canInstantiateShip:shipKey]) return shipKey;
// Condition failed -> remove ship from consideration.
[pset removeObject:shipKey];
}
---------------------------------------------------------------------------------
- (void) removeObject:(id)object
{
// if (object != nil) return; caused not to remove object
OOLog(@"bane",@"removing %@",(NSString*)object);
OOUInteger index = [_objects indexOfObject:object];
if(index == NSNotFound)OOLog(@"bane",@"%@ not found!",(NSString*)object);
if (index != NSNotFound)
{
[_objects removeObjectAtIndex:index];
_sumOfWeights -= [_weights floatAtIndex:index];
[_weights removeObjectAtIndex:index];
}
}
------------------------------------------------------------------------------
there is final problem which is that randomObject returns nil
if MutableProbabilitySet already contains objects,
so I have made counter 'i' to avoid endless loop.
TridentDown now loads properly, but it has ships I think
which cannot be instantiated that caused endless loop.
The crash that has been torturing us since the release of 1.72 was actually inside OOProbabilitySet.m, -(void) removeObject: (id) object method, as you point out. But instead of just commenting the line out, it should be changed from
I have not had the time to test anything else, but for sure Commies.oxp (and most likely any other OXP adding ships with conditions) is not crashing anymore.
Good job bmaxa, looking forward to the next bugfix.
I think there must be a “Guardian angel” of some kind for oolite
In 1.70 & 1.71 we had Kaks came out from nowhere killing numerous bugs at no time and now that kaks is missing (Where are you man?? ) bmaxa came out of the blue doing the same think
God save oolite man!!!!!
Last edited by Ark on Fri Nov 07, 2008 5:13 pm, edited 1 time in total.
Another thing is I'm compiling on ubuntu 8.10 amd64 and got
these warnings about pset count not used from OOMutableSet
but from NSArray as methods have same name?
I can swear that count was not decreased before I changed name
count to countPS, though perhaps I'm wrong.
I can swear that count was not decreased before I changed name
count to countPS, though perhaps I'm wrong.
The count was not decreased because no object was ever removed from the probability set. The removeObject method was always returning without doing anything, therefore the count was always the same, therefore endless loop.
I have returned method name to count and is decreasing anyway,
you are absolutely right. Seems that I first changed method name
to countPS then commented out line
I'm sorry to bother again but bug is not cleared out with just
if condition in removeObject.
Other part of bug is in shipKey = [registry randomShipKeyForRole:role];
because it will call randomObject alright, but on other set, which
does not guarantees that all object will come out eventualy
as there are objects with zero weights. As expected TridentDown
loops more then 1000- times.
so proper solution for this loop is
--------------------------------------------------------
while ([pset count] > 0)
{
// Select a ship, check conditions and return it if possible.
//shipKey = [registry randomShipKeyForRole:role];
// does not guarantees that all objects will come out
// and spends much more time then necessary
shipKey = [pset randomObject]; // this is correct I think
// as same object will not be returned twice
if(shipKey == nil)
{
break; // there are no more objects with non zero weight
}
if ([self canInstantiateShip:shipKey]) return shipKey;
// Condition failed -> remove ship from consideration.
[pset removeObject:shipKey];
}
-------------------------------------------------------
randomObject will return all objects that don;t have weight zero
but when cumulative weight reaches 0 it will return nil so that
means that we should break from loop.