• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: NSMutableArray + NSEnumerator = No Memory
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NSMutableArray + NSEnumerator = No Memory


  • Subject: Re: NSMutableArray + NSEnumerator = No Memory
  • From: James Bucanek <email@hidden>
  • Date: Sun, 23 Sep 2007 11:35:39 -0700

glenn andreas <mailto:email@hidden> wrote (Saturday, September 22, 2007 1:52 PM -0500):

On Sep 22, 2007, at 3:20 PM, James Bucanek wrote:

Bill Bumgarner <mailto:email@hidden> wrote (Saturday, September 22, 2007 12:05 PM -0700):

On Sep 22, 2007, at 11:36 AM, James Bucanek wrote:
1 - Use objectAtIndex: to iterate through the array.

2 - Create an auto release pool and discard the NSEnumerator during every search.

This is likely a good idea to do regardless of the rest of the problem as it is likely that you are causing, directly or indirectly, temporary objects to be created. Dumping 'em every so often when doing lots of looping is generally a good idea.

I was doing that already (once per collection), but not aggressively enough to avoid this problem. In fact, if the NSEnumerator wasn't making whole copies of the entire array every time a new enumerator was created, there wouldn't be any problem at all. During the search loop, I really only expected one object (the enumerator) to be created, so at most there would have been N objects created per auto release pool.

Let's just try an experiment:

#include <Foundation/Foundation.h>
#include <stdio.h>

int main(int argc, const char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *a = [NSMutableArray array];
for (int i=0;i<30000;i++) {
[a addObject: [NSNumber numberWithInt: i]];
}
NSLog(@"%d objects",[a count]);
NSEnumerator *e1 = [a objectEnumerator];
NSNumber *v1;
while ((v1 = [e1 nextObject]) != nil) {
NSAutoreleasePool *p2 = [[NSAutoreleasePool alloc] init];
BOOL show = ([v1 intValue] % 1000) == 0;
if (show) NSLog(@"%@",v1);
NSEnumerator *e2 = [a objectEnumerator];
NSNumber *v2;
while ((v2 = [e2 nextObject]) != nil) {
if ([v1 isEqualTo: v2]) {
if (show) NSLog(@"%@ = %@", v1, v2);
break;
}
}
[p2 release];
}
NSLog(@"Enumerator %@, v1 = %@",e1,v1);
return 0;
}


Thanks, Glenn. That's pretty close to my test app.

If I compile and run this, here's what top says:

PID COMMAND      %CPU   TIME   #TH #PRTS #MREGS RPRVT  RSHRD  RSIZE  VSIZE
16881 a.out       88.5%  0:04.88   1    13    31  1.23M   624K  4.00M  36.7M

It does take a while to fully execute, but memory usage never goes above this.

If p2 is created _after_ e2 (so e2 is in the outer pool), memory skyrockets, everything comes to a screeching halt.

So the behavior might be a bit surprising, but the solution is simple.

Not really. The enumerator might still be making duplicates of the entire collection, this code just recovers the memory each time before returning. I'm not particularly worried about the overhead of creating an extra autorelease pool, but the idea of duplicating the entire collection every time it gets searched is a horrific performance hit for large collections.


It appears that this only occurs when there are unreleased NSEnumerator objects that haven't finished enumerating through the collection. If this was single-threaded code that could guarantee that the enumerator got released before returning, that would probably prevent the problem (duplicating the array) from occurring. But this is multi-threaded code and without adding synchronization locks to the code, there's no way to prevent two or more enumerators from existing at the same time. (Nor, should I have to in my NSHO.)

(For the record, it doesn't seem to matter if the array is mutable or not - making an immutable copy of the array appears to have the same problem)

Which makes the problem even more bizarre, in my mind.

--
James Bucanek

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


References: 
 >Re: NSMutableArray + NSEnumerator = No Memory (From: glenn andreas <email@hidden>)

  • Prev by Date: Re: NSArrayController question
  • Next by Date: Re: NSMutableArray + NSEnumerator = No Memory
  • Previous by thread: Re: NSMutableArray + NSEnumerator = No Memory
  • Next by thread: Re: NSMutableArray + NSEnumerator = No Memory
  • Index(es):
    • Date
    • Thread