Re: [Pyobjc-dev] Reference Counting
Brought to you by:
ronaldoussoren
From: Ronald O. <ous...@ci...> - 2004-04-08 18:21:02
|
On 8-apr-04, at 17:54, Michael Tsai wrote: > will use memory without bound unless I put in an autorelease pool: > > while 1: > pool = NSAutoreleasePool.alloc().init() > NSArray.array() > pool.release() The release is not necessary, 'pool = None' or 'del pool' also do the trick. See below for an explanation. > > I thought I might be able to get away with: > > while 1: > pool = NSAutoreleasePool.alloc().init() > NSArray.array() I found what's causing this. Due to the way python and PyObjC work this code above is equivalent to: NSObject* oldpool; NSObject* pool; while (1) { oldpool = pool; pool = [[NSAutoreleasePool alloc] init]; [oldpool release]; [NSArray array]; } If you run this code you'll notice lots of messages on stderr: It's complaining that an NSArray instance is leaked due to missing an autorelease pool. You don't see that in python because the objc module creates a pool when it is loaded, this is necessary to be able to use Cocoa at all. ... Hmm, to be more precise it used to be required, I suppose we could nowadays require the user to create a pool. Something else to look into. I'm not sure why Cocoa behaves like this, but this might be the intended behaviour. The documentation for NSAutoreleasePool explictly mentions that pools behave like a stack, I suppose the implementation doesn't like it when you pop the second highest entry of that stack. There's not much we can do about that, other than documenting this fact. I have added some notes to the documentation about this issue. > > because at the start of each loop there are no more Python references > to > the old pool. What happens, though, is that memory use gradually grows, > albeit slower than in the case with just NSArray.array() and no pool. > > Strings behave differently from arrays. This doesn't run in a constant > amount of memory: > > while 1: > NSString.alloc().init() That's because the conversion from Cocoa to Python uses an autoreleased object. That will be changed soon, for other reasons. > > So, it seems that the bridge relieves me from calling retain, > release, and autorelease, but that I still have to make sure that > there is a pool in place and that it is emptied now and then. If the > pool is created in Python, it must be released by calling > pool.release(); Python's GC somehow doesn't do the right thing. Is > this correct? Almost correct. You must make sure that the old pool is gone before you create a new one. pool.release() is unsafe, this should cause serious problems because the bridge will also call -release later on (oddly enough this doesn't cause problems, probably an implementation artifact). I'd use 'del pool' to make it explicit that I'm killing off the old pool before creating the new one. Ronald -- X|support bv http://www.xsupport.nl/ T: +31 610271479 F: +31 204416173 |