NSAutoreleasePool: how does it really work?
-
I don't understand yet how does NSAutoreleasePool really work.
At the end of the following loop, the "top" command tells me that the Rsize
of my application doesn't decrease anymore. Instead I expect that it should
return to the initial value because I remove all the objects from the
xArray. I get lack of memory all the time. I know that "addObject" retains
the object just added, but, how to free up the memory at the end?
===============================
- (void)MyLoop
{
int i;
xArray = [NSMutableArray arrayWithCapacity:0];
for(i = 0; i < 500000; i++){
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
NSString *sourceItem = [[NSString alloc]
initWithFormat:@"Item number %d", i];
[sourceItem autorelease];
[xArray addObject:sourceItem];
[myPool release];
}
[xArray removeAllObjects];
}
===============================
If I use only:
===============================
- (void)MyLoop
{
int i;
xArray = [NSMutableArray arrayWithCapacity:0];
for(i = 0; i < 500000; i++){
[xArray addObject:@"abc"];
}
[xArray removeAllObjects];
}
===============================
it works well: at the end of the loop, the Rsize returns to the initial
value.
Where can I learn more about NSAutoreleasePool? I already read the
documentation, but it seems to be not enough. And what did I do wrong?
Best Regards
--
Lorenzo Puleo
email: <archidea...>
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi,
In> ===============================
> - (void)MyLoop
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
> NSString *sourceItem = [[NSString alloc]
> initWithFormat:@"Item number %d", i];
> [sourceItem autorelease];
> [xArray addObject:sourceItem];
> [myPool release];
> }
> [xArray removeAllObjects];
> }
> ===============================
the pool releases NOTHING but itself, because all items get created with
retain count = 1, then they get scheduled for autorelease (retCount--) and
then retained by the NSArray (retCount++).
I don't know how this can result in memory leaks, though...
Any way, this code is NOT the same as the one that does not produce leaks
because
(1) [xArray addObject:[NSString stringWithFormat:@"Item number %d", i]];
(actually, it does all the same the above fragment)
is significantly different from
(2) [xArray addObject:@"abc"];
I would suggest such experimental pair:> ===============================
> - (void)MyLoop1
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++)
> {
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
> [xArray addObject:[NSString stringWithFormat:@"Do leak, step %d", i]];
> [myPool release];
> }
> [xArray removeAllObjects];
> }
> ===============================
against> ===============================
> - (void)MyLoop2
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> [xArray addObject:[NSString stringWithFormat:@"Don\'t leak, step %d", i]];
> }
> [xArray removeAllObjects];
> }
> ===============================
and then compare results. IMHO, they BOTH should not leak. :(
Regards
Oleg> I don't understand yet how does NSAutoreleasePool really work._______________________________________________
> At the end of the following loop, the "top" command tells me that the Rsize
> of my application doesn't decrease anymore. Instead I expect that it should
> return to the initial value because I remove all the objects from the
> xArray. I get lack of memory all the time. I know that "addObject" retains
> the object just added, but, how to free up the memory at the end?
>
> ===============================
> - (void)MyLoop
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
> NSString *sourceItem = [[NSString alloc]
> initWithFormat:@"Item number %d", i];
> [sourceItem autorelease];
> [xArray addObject:sourceItem];
> [myPool release];
> }
> [xArray removeAllObjects];
> }
> ===============================
>
>
>
> If I use only:
> ===============================
> - (void)MyLoop
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> [xArray addObject:@"abc"];
> }
> [xArray removeAllObjects];
> }
> ===============================
> it works well: at the end of the loop, the Rsize returns to the initial
> value.
>
> Where can I learn more about NSAutoreleasePool? I already read the
> documentation, but it seems to be not enough. And what did I do wrong?
>
>
>
> Best Regards
> --
> Lorenzo Puleo
> email: <archidea...>
> _______________________________________________
> cocoa-dev mailing list | <cocoa-dev...>
> Help/Unsubscribe/Archives:
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev
> Do not post admin requests to the list. They will be ignored.
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi Oleg,
I tried both the samples you granted (MyLoop1 and MyLoop2), and they
produced the same lack of memory.
Before launching the routine I have:
PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
1301 MyApp 0.0% 0:01.07 1 60 138 3.03M 7.39M 8.61M 105M
And after my routine ends I get:
PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
1301 MyApp 0.0% 0:06.88 1 60 237 27.7M 7.41M 33.3M+ 130M
The RSIZE value remains at 33.3M and never goes down. Sure I don't do
anything else, either before and after the routine. I also tried to attach
this routine to the button directly as:
- (IBAction)MyLoop2:(id)sender
{
int i;
xArray = [NSMutableArray arrayWithCapacity:0];
for(i = 0; i < 500000; i++){
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
[xArray addObject:[NSString stringWithFormat:@"Do leak, step %d",
i]];
[myPool release];
}
[xArray removeAllObjects];
}
Any idea?
Best Regards
--
Lorenzo Puleo
email: <archidea...>> From: Oleg Svirgstin <olegsvir...>_______________________________________________
> Date: Tue, 18 Mar 2003 13:15:26 +0300
> To: <cocoa-dev...>
> Cc: Lorenzo Puleo <archidea...>
> Subject: Re: NSAutoreleasePool: how does it really work?
>
> I would suggest such experimental pair:
>
>> ===============================
>> - (void)MyLoop1
>> {
>> int i;
>> xArray = [NSMutableArray arrayWithCapacity:0];
>> for(i = 0; i < 500000; i++)
>> {
>> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
>> [xArray addObject:[NSString stringWithFormat:@"Do leak, step %d", i]];
>> [myPool release];
>> }
>> [xArray removeAllObjects];
>> }
>> ===============================
>
> against
>
>> ===============================
>> - (void)MyLoop2
>> {
>> int i;
>> xArray = [NSMutableArray arrayWithCapacity:0];
>> for(i = 0; i < 500000; i++){
>> [xArray addObject:[NSString stringWithFormat:@"Don\'t leak, step %d", i]];
>> }
>> [xArray removeAllObjects];
>> }
>> ===============================
>
> and then compare results. IMHO, they BOTH should not leak. :(
>
> Regards
> Oleg
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
On Tuesday, Mar 18, 2003, at 12:20 Europe/Zurich, Lorenzo Puleo wrote:> - (IBAction)MyLoop2:(id)sender
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc]
> init];
> [xArray addObject:[NSString stringWithFormat:@"Do leak, step
> %d",
> i]];
> [myPool release];
> }
> [xArray removeAllObjects];
> }
>
> Any idea?
Your array is retaining your strings. The pool allocation/deallocation
inside the loop is frivolous.
If for some reasons you want to micromanage your memory pool, try:
NSAutoreleasePool* aPool = [[NSAutoreleasePool alloc] init];
int count = 500000;
int index = 0;
NSMutableArray* anArray = [NSMutableArray arrayWithCapacity: count];
for ( index = 0; index < count; index++ )
{
[anArray addObject:[NSString stringWithFormat: @"Don't leak, step
%d", index]];
}
[aPool release];
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
G'Day Lorenzo!> I don't understand yet how does NSAutoreleasePool really work.
> At the end of the following loop, the "top" command tells me that the Rsize
> of my application doesn't decrease anymore. Instead I expect that it should
> return to the initial value because I remove all the objects from the
> xArray. I get lack of memory all the time. I know that "addObject" retains
> the object just added, but, how to free up the memory at the end?
>
This is my spin on how it all works (and I'd welcome any corrections and
clarifications).
Firstly:
1. Each object you create has a retain count.
2. Sending a "retain" message to an object causes its retain count to be
incremented by one.
3. Sending a "release" message to an object causes its retain count to
be decremented by one.
4. When a "release" message causes the retain count of an object to be
decremented to zero, the memory associated with the object is freed.
5. Sending an "autorelease" message to an object does nothing to the
retain count. It merely adds the object to the autorelease pool. When
the autorelease pool is released, the objects in the pool are sent
release messages at that time.
Secondly, there are two ways in which an object can be created:
1. Factory methods (such as NSMutableArray's arrayWithCapacity) return
the object with a retain count of one, but also autoreleased.
Therefore, if you want such an object to hang around, you need to
send it a retain message, plus either a release or an autorelease
when you no longer need it.
2. The alloc/init sequence (or other initializer variants like NSString's
initWithFormat) returns the object with a retain count of one. Therefore,
you always need to send such an object a release or autorelease message
when you no longer need it.
Thirdly, how the autorelease pool is managed is a function of what kind of
application you are writing:
1. For a cocoa application, an autorelease pool is created at the
beginning of each event loop, and released at the end of that
event loop. You don't need to think about this.
2. For any other kind of application, you need to manage it yourself.
Personally, I have found a two-level approach to be effective.
For example:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * applicationPool = [[NSAutoreleasePool alloc] init];
// initialization code goes here. Any objects auto-released during
// this phase go to applicationPool but will be available for the
// life of the application, as you would hope and expect.
// enter main loop
while (running) {
// instantiate a per-loop autorelease pool
NSAutoreleasePool * loopPool = [[NSAutoreleasePool alloc] init];
// do some useful work. Any objects auto-released during this
// pass through the loop go to loopPool, will only be available
// during this pass through the loop, and will disappear at
// the end of the loop.
// release the per-loop pool
[loopPool release];
}
// release the application pool
[applicationPool release];
return 0;
}
Finally, although this repeats some of what I wrote above, you need to keep
these rules in mind:
1. An object created by a factory method is autoreleased. If you do nothing
else, it will disappear automatically when its autorelease pool is
released. For a cocoa app, that's at the end of the current event loop.
2. An object created via alloc/init is not auto-released. You must balance
each alloc/init with either a release or an autorelease.
3. For each and every object to which you send a retain, you must also send
a matching release or autorelease.> ===============================
> - (void)MyLoop
> {
> int i;
> NSMutableArray * xArray = [NSMutableArray arrayWithCapacity:0];
xArray is created via a factory method and is, therefore, auto-released. An
autorelease pool which exists outside the scope of MyLoop will have taken
note of the autorelease message sent to xArray during its creation.> for(i = 0; i < 500000; i++){
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
now you've created an autorelease pool that will only exist inside the
scope of the for-loop, and for a single iteration of the for-loop.> NSString *sourceItem = [[NSString alloc]
> initWithFormat:@"Item number %d", i];
sourceItem is allocated with a retain-count of one.> [sourceItem autorelease];
myPool now knows about sourceItem and will send it a release message when
myPool is autoreleased. The retain count of sourceItem is still 1.> [xArray addObject:sourceItem];
sourceItem is added to xArray which sends it a retain message. Its retain
count is now 2.> [myPool release];
myPool sends each instance of sourceItem a release message. The retain
count of each instance will now be 1. None of the items will actually be
released because xArray still "owns" them.> }
> [xArray removeAllObjects];
xArray sends each object a release message, causing the retain count for
all sourceItem objects to become zero, so all sourceItem objects are
destroyed. You can prove to yourself that this is occurring by overriding
the dealloc method and writing a message.
xArray, however, still exists because the autorelease pool to which it was
allocated has not been released.
In my own testing, the objects are sent dealloc messages at exactly the
times I expect. Therefore, either you are doing something different or
Rsize isn't telling you what you think it is telling you.
On that subject, my understanding of Rsize is that it reports the number of
real pages of memory currently allocated to the process. I may be wrong but
I doubt that releasing objects within an application will have any
correlation with the amount of real memory allocated to that application. I
doubt that the number will reduce until such time as the page manager needs
to recover some real memory and pages something out.> }
> ===============================
>
>
>
> If I use only:
> ===============================
> - (void)MyLoop
> {
> int i;
> xArray = [NSMutableArray arrayWithCapacity:0];
> for(i = 0; i < 500000; i++){
> [xArray addObject:@"abc"];
Here, you are not actually creating an object each time you pass through
the loop. You are merely adding a reference to the same static @"abc"
object. During the addObject, xArray sends the retain message and the
removeAllObjects below sends the corresponding release message. However,
@"abc" will continue to exist for the life of the application. Objects like
@"abc" have a retain count of -1. You can send any number of retain,
release and autorelease messages to such objects and the retain count
remains at -1. So, in effect, you aren't creating anything and aren't
destroying anything.> }
> [xArray removeAllObjects];
The same caveats apply to xObject as in the first example. xObject is
created and autoreleased by the factory method; the autorelease pool exists
outside the scope of this routine; xObject won't be released until its
autorelease pool is released.> }> ===============================
> it works well: at the end of the loop, the Rsize returns to the initial
> value.
Almost certainly due to the fact that you aren't allocating a lot of objects.> Where can I learn more about NSAutoreleasePool? I already read the
> documentation, but it seems to be not enough. And what did I do wrong?
I hope this helps.
Regards, PK
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi Phill,
Thank you for your detailed reply. You gave me fine informations.
I think Rsize means Real Size an application is using. More than this I can
see the Free Memory decreases while the Rsize increases. Look here belowe
the free memory is 328M before running the routine and 302M at the end.
Before running the routine
===========================
Processes: 43 total, 2 running, 41 sleeping... 103 threads
16:11:18
Load Avg: 0.56, 0.40, 0.34 CPU usage: 52.6% user, 17.5% sys, 29.8% idl
SharedLibs: num = 90, resident = 20.5M code, 2.61M data, 7.36M LinkEdit
MemRegions: num = 2392, resident = 16.8M + 8.26M private, 35.2M shared
PhysMem: 46.9M wired, 56.5M active, 81.1M inactive, 184M used, 328M free
VM: 2.00G + 51.8M 5047(1) pageins, 0(0) pageouts
PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
409 MyApp 0.0% 0:00.99 1 60 130 3.00M 7.04M 8.57M 105M
After running the routine
===========================
Processes: 43 total, 2 running, 41 sleeping... 104 threads
16:11:50
Load Avg: 0.25, 0.35, 0.31 CPU usage: 2.9% user, 3.8% sys, 93.3% idle
SharedLibs: num = 90, resident = 20.7M code, 2.61M data, 7.36M LinkEdit
MemRegions: num = 2512, resident = 41.7M + 8.26M private, 35.5M shared
PhysMem: 47.1M wired, 56.9M active, 106M inactive, 210M used, 302M free
VM: 2.03G + 51.8M 5109(0) pageins, 0(0) pageouts
PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
409 MyApp 0.0% 0:05.77 1 60 229 27.7M 7.14M 33.2M 130M
This time I used the following code:
===========================
- (IBAction)MyLoop:(id)sender
{
int i;
xArray = [NSMutableArray array];
for ( i = 0; i < 500000; i++ )
{
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
[xArray addObject:[NSString stringWithFormat: @"Don't leak, step
%d", i]];
[myPool release];
}
[xArray removeAllObjects];
return;
}
Sincerely I am afraid that I am doing something wrong.
If I run the loop for a bigger number of steps (100,000,000)
I see the free memory goes near zero, then the numbers of pageouts
increases. And at the end of the routine, my application keeps the CPU busy
for so long time because it has to clean the files used by the virtual
memory. And however the Rsize and the Free Mem don't come back to the
initial values.
Best Regards
--
Lorenzo Puleo
email: <archidea...>
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Have you verified that your output from top or ps is accurate? In other
words, written a simple application where you don't autorelease? So,
just write a simple application and verify that your monitoring
methodology is accurate. I seem to remember that those numbers are
flaky at best in terms of accuracy... but, maybe that's just a linux
thing (where most of my experience is...).
Sujal
On Tue, 2003-03-18 at 10:35, Lorenzo Puleo wrote:> Hi Phill,--
> Thank you for your detailed reply. You gave me fine informations.
>
> I think Rsize means Real Size an application is using. More than this I can
> see the Free Memory decreases while the Rsize increases. Look here belowe
> the free memory is 328M before running the routine and 302M at the end.
>
> Before running the routine
> ===========================
> Processes: 43 total, 2 running, 41 sleeping... 103 threads
> 16:11:18
> Load Avg: 0.56, 0.40, 0.34 CPU usage: 52.6% user, 17.5% sys, 29.8% idl
> SharedLibs: num = 90, resident = 20.5M code, 2.61M data, 7.36M LinkEdit
> MemRegions: num = 2392, resident = 16.8M + 8.26M private, 35.2M shared
> PhysMem: 46.9M wired, 56.5M active, 81.1M inactive, 184M used, 328M free
> VM: 2.00G + 51.8M 5047(1) pageins, 0(0) pageouts
>
> PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
> 409 MyApp 0.0% 0:00.99 1 60 130 3.00M 7.04M 8.57M 105M
>
>
> After running the routine
> ===========================
> Processes: 43 total, 2 running, 41 sleeping... 104 threads
> 16:11:50
> Load Avg: 0.25, 0.35, 0.31 CPU usage: 2.9% user, 3.8% sys, 93.3% idle
> SharedLibs: num = 90, resident = 20.7M code, 2.61M data, 7.36M LinkEdit
> MemRegions: num = 2512, resident = 41.7M + 8.26M private, 35.5M shared
> PhysMem: 47.1M wired, 56.9M active, 106M inactive, 210M used, 302M free
> VM: 2.03G + 51.8M 5109(0) pageins, 0(0) pageouts
>
> PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
> 409 MyApp 0.0% 0:05.77 1 60 229 27.7M 7.14M 33.2M 130M
>
>
> This time I used the following code:
> ===========================
> - (IBAction)MyLoop:(id)sender
> {
> int i;
> xArray = [NSMutableArray array];
>
> for ( i = 0; i < 500000; i++ )
> {
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
> [xArray addObject:[NSString stringWithFormat: @"Don't leak, step
> %d", i]];
> [myPool release];
> }
> [xArray removeAllObjects];
> return;
>
> }
>
>
> Sincerely I am afraid that I am doing something wrong.
> If I run the loop for a bigger number of steps (100,000,000)
> I see the free memory goes near zero, then the numbers of pageouts
> increases. And at the end of the routine, my application keeps the CPU busy
> for so long time because it has to clean the files used by the virtual
> memory. And however the Rsize and the Free Mem don't come back to the
> initial values.
>
>
> Best Regards
---- Sujal Shah --- <sujal...> ---
http://www.sujal.net
Now Playing: George Michael - Listen Without Prejudice - 001 - Praying for time
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
On Tuesday, Mar 18, 2003, at 11:39 US/Eastern,
<cocoa-dev-request...> wrote:
... analysis deleted ...> - (IBAction)MyLoop:(id)sender
> {
> int i;
> xArray = [NSMutableArray array];
>
> for ( i = 0; i < 500000; i++ )
> {
> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc]
> init];
> [xArray addObject:[NSString stringWithFormat: @"Don't leak,
> step
> %d", i]];
> [myPool release];
> }
> [xArray removeAllObjects];
> return;
> }
The release pool in the above code doesn't actually do anything (except
slowing down the code)!
The @"..." format string is statically allocated; there should be only
one.
The string instance produced by -stringWithFormat: is autoreleased into
myPool, by you shove it into an array inside of myPool's scope. This
ensures that the string is persisted beyond the call to -release on
myPool.
If you were to remove the allocation of myPool, you will likely see a
reduction in the memory usage because of fewer object creation/deletion
events to potentially fragment the heap.
b.bum
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Ok Bill, thank you,
but please what can I do now? How should I modify my code in order to use
the memory properly? I am trying all the time, unsuccessfully. The unix
"top" command tells me that Rsize and Free Mem never come back to the
initial values.
Should I still
Best Regards
--
Lorenzo Puleo
email: <archidea...>
compact the heap like in Carbon?
Best Regards
--
Lorenzo Puleo
email: <archidea...>> From: Bill Bumgarner <bbum...>_______________________________________________
> Date: Tue, 18 Mar 2003 11:55:55 -0500
> To: <cocoa-dev...>
> Cc: Lorenzo Puleo <archidea...>, Phill Kelley <pkelle2...>
> Subject: Re: NSAutoreleasePool: how does it really work?
>
> On Tuesday, Mar 18, 2003, at 11:39 US/Eastern,
> <cocoa-dev-request...> wrote:
> ... analysis deleted ...
>> - (IBAction)MyLoop:(id)sender
>> {
>> int i;
>> xArray = [NSMutableArray array];
>>
>> for ( i = 0; i < 500000; i++ )
>> {
>> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc]
>> init];
>> [xArray addObject:[NSString stringWithFormat: @"Don't leak,
>> step
>> %d", i]];
>> [myPool release];
>> }
>> [xArray removeAllObjects];
>> return;
>> }
>
> The release pool in the above code doesn't actually do anything (except
> slowing down the code)!
>
> The @"..." format string is statically allocated; there should be only
> one.
>
> The string instance produced by -stringWithFormat: is autoreleased into
> myPool, by you shove it into an array inside of myPool's scope. This
> ensures that the string is persisted beyond the call to -release on
> myPool.
>
> If you were to remove the allocation of myPool, you will likely see a
> reduction in the memory usage because of fewer object creation/deletion
> events to potentially fragment the heap.
>
> b.bum
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Ok Bill, thank you,
but please what can I do now? How should I modify my code in order to use
the memory properly? I am trying all the time, unsuccessfully. The unix
"top" command tells me that Rsize and Free Mem never come back to the
initial values.
Should I still
Best Regards
--
Lorenzo Puleo
email: <archidea...>
compact the heap like in Carbon?
Best Regards
--
Lorenzo Puleo
email: <archidea...>> From: Bill Bumgarner <bbum...>_______________________________________________
> Date: Tue, 18 Mar 2003 11:55:55 -0500
> To: <cocoa-dev...>
> Cc: Lorenzo Puleo <archidea...>, Phill Kelley <pkelle2...>
> Subject: Re: NSAutoreleasePool: how does it really work?
>
> On Tuesday, Mar 18, 2003, at 11:39 US/Eastern,
> <cocoa-dev-request...> wrote:
> ... analysis deleted ...
>> - (IBAction)MyLoop:(id)sender
>> {
>> int i;
>> xArray = [NSMutableArray array];
>>
>> for ( i = 0; i < 500000; i++ )
>> {
>> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc]
>> init];
>> [xArray addObject:[NSString stringWithFormat: @"Don't leak,
>> step
>> %d", i]];
>> [myPool release];
>> }
>> [xArray removeAllObjects];
>> return;
>> }
>
> The release pool in the above code doesn't actually do anything (except
> slowing down the code)!
>
> The @"..." format string is statically allocated; there should be only
> one.
>
> The string instance produced by -stringWithFormat: is autoreleased into
> myPool, by you shove it into an array inside of myPool's scope. This
> ensures that the string is persisted beyond the call to -release on
> myPool.
>
> If you were to remove the allocation of myPool, you will likely see a
> reduction in the memory usage because of fewer object creation/deletion
> events to potentially fragment the heap.
>
> b.bum
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
On Tuesday, March 18, 2003, at 10:52 AM, Sujal Shah wrote:> Have you verified that your output from top or ps is accurate? In
> other
> words, written a simple application where you don't autorelease? So,
> just write a simple application and verify that your monitoring
> methodology is accurate. I seem to remember that those numbers are
> flaky at best in terms of accuracy... but, maybe that's just a linux
> thing (where most of my experience is...).
>
> Sujal
With some compilers and C-libraries there are multiple layers of
allocation. That is, the library gets big chunks of memory from the
system, and then parcels them out via its own allocation scheme to
malloc, new, and alloc requests. It's possible that's what's happening
here, with memory being freed at an application level but not a system
level.
-- Andres
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
IMHO, NSAutoreleasePool works fantastic, the only thing it is unfortunately
missing is capability to show, say, class of the offending object.
Say, in some super-debug mode. Say, representing zero refcount as 1 000 000,
and raising with details on every instance asked to release being 1 000 000
or less. Or deallocate instances when their recount reaches, say, - 1 000
000.
PoolBombSquad mode. Finding all possible information about the crasher.
Such pool accidents killed a lot of my time and nerves few months ago, and
now, though rarely, such things do happen... Multiplied by thousands of
newbies this time grows into lost, sad and nervous millennia...
Wow, is there a solution within our reach? It would be a nice little tool...
And now let me enjoy some RANT... I love flames, rants and everything that
takes me away from programming for few happy minutes.
Indeed, there must be some secret life behind every applications' back...
Why should we know everything about their PRIVATE life? Do not oppress them
too much, and they will generally just work.
How often in the real life do we need loops of 500 000 iterations where
every step allocates and deallocates ObjC instances?
Even if there is a need for such an infinite loop, it is an obvious subject
to severe optimization of its body by all means... It is a point where NO
memory allocations in traditional way should happen. Probably nothing but
plain C is good there. As much as possible of operations must be put outside
the loop's body.
Here we just allocate, allocate, resize and deallocate. If I were mach
kernel, I would run to the wood...
Well, we don't even know how we ourselves work... :)
Regards
Oleg> From: Sujal Shah <sujal...>_______________________________________________
> Date: 18 Mar 2003 10:52:10 -0500
> To: <cocoa-dev...>
> Subject: Re: NSAutoreleasePool: how does it really work?
>
> Have you verified that your output from top or ps is accurate? In other
> words, written a simple application where you don't autorelease? So,
> just write a simple application and verify that your monitoring
> methodology is accurate. I seem to remember that those numbers are
> flaky at best in terms of accuracy... but, maybe that's just a linux
> thing (where most of my experience is...).
>
> Sujal
>
>
> On Tue, 2003-03-18 at 10:35, Lorenzo Puleo wrote:
>> Hi Phill,
>> Thank you for your detailed reply. You gave me fine informations.
>>
>> I think Rsize means Real Size an application is using. More than this I can
>> see the Free Memory decreases while the Rsize increases. Look here belowe
>> the free memory is 328M before running the routine and 302M at the end.
>>
>> Before running the routine
>> ===========================
>> Processes: 43 total, 2 running, 41 sleeping... 103 threads
>> 16:11:18
>> Load Avg: 0.56, 0.40, 0.34 CPU usage: 52.6% user, 17.5% sys, 29.8% idl
>> SharedLibs: num = 90, resident = 20.5M code, 2.61M data, 7.36M LinkEdit
>> MemRegions: num = 2392, resident = 16.8M + 8.26M private, 35.2M shared
>> PhysMem: 46.9M wired, 56.5M active, 81.1M inactive, 184M used, 328M free
>> VM: 2.00G + 51.8M 5047(1) pageins, 0(0) pageouts
>>
>> PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
>> 409 MyApp 0.0% 0:00.99 1 60 130 3.00M 7.04M 8.57M 105M
>>
>>
>> After running the routine
>> ===========================
>> Processes: 43 total, 2 running, 41 sleeping... 104 threads
>> 16:11:50
>> Load Avg: 0.25, 0.35, 0.31 CPU usage: 2.9% user, 3.8% sys, 93.3% idle
>> SharedLibs: num = 90, resident = 20.7M code, 2.61M data, 7.36M LinkEdit
>> MemRegions: num = 2512, resident = 41.7M + 8.26M private, 35.5M shared
>> PhysMem: 47.1M wired, 56.9M active, 106M inactive, 210M used, 302M free
>> VM: 2.03G + 51.8M 5109(0) pageins, 0(0) pageouts
>>
>> PID COMMAND %CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE
>> 409 MyApp 0.0% 0:05.77 1 60 229 27.7M 7.14M 33.2M 130M
>>
>>
>> This time I used the following code:
>> ===========================
>> - (IBAction)MyLoop:(id)sender
>> {
>> int i;
>> xArray = [NSMutableArray array];
>>
>> for ( i = 0; i < 500000; i++ )
>> {
>> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
>> [xArray addObject:[NSString stringWithFormat: @"Don't leak, step
>> %d", i]];
>> [myPool release];
>> }
>> [xArray removeAllObjects];
>> return;
>>
>> }
>>
>>
>> Sincerely I am afraid that I am doing something wrong.
>> If I run the loop for a bigger number of steps (100,000,000)
>> I see the free memory goes near zero, then the numbers of pageouts
>> increases. And at the end of the routine, my application keeps the CPU busy
>> for so long time because it has to clean the files used by the virtual
>> memory. And however the Rsize and the Free Mem don't come back to the
>> initial values.
>>
>>
>> Best Regards
> --
> ---- Sujal Shah --- <sujal...> ---
>
> http://www.sujal.net
>
> Now Playing: George Michael - Listen Without Prejudice - 001 - Praying for
> time
> _______________________________________________
> cocoa-dev mailing list | <cocoa-dev...>
> Help/Unsubscribe/Archives:
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev
> Do not post admin requests to the list. They will be ignored.
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
> IMHO, NSAutoreleasePool works fantastic, the only thing it is
> unfortunately
> missing is capability to show, say, class of the offending object.
>
> Say, in some super-debug mode. Say, representing zero refcount as 1
> 000 000,
> and raising with details on every instance asked to release being 1
> 000 000
> or less. Or deallocate instances when their recount reaches, say, - 1
> 000
> 000.
>
> PoolBombSquad mode. Finding all possible information about the crasher.
>
> Such pool accidents killed a lot of my time and nerves few months ago,
> and
> now, though rarely, such things do happen... Multiplied by thousands of
> newbies this time grows into lost, sad and nervous millennia...
>
> Wow, is there a solution within our reach? It would be a nice little
> tool...
Yes, there is a solution. You may continue to call it PoolBombSquad
mode, but in reality it's called NSZombieEnabled. It is an environment
variable. You should activate it in your Executable in PB by adding an
environment variable with that name, and the value "YES".
What the feature does, is that it leaves deallocated objects around, in
sort of a zombie mode. When they are then messaged, for example by
NSAutoreleasePool, you will get an informational message about the
receiver (it's class, address etc).
Read more in <Foundation/NSDebug.h>.
/ Rgds, David Remahl
_______________________________________________
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi Oleg,
the problem is not the 500,000 iterations.
I did that just to see better what was happening.
Also the iterations could be 100,000 and the objects allocated could be 5
per each iteration...
The problem is that the unix "top" command in the Terminal tells me that the
RSIZE of my application and the FREE memory don't come back to the initial
values, after I have released the objects. So I would like to understand
better what is happening.
Best Regards
--
Lorenzo Puleo
email: <archidea...>> From: <cocoa-dev-request...>_______________________________________________
> Reply-To: <cocoa-dev...>
> Date: Tue, 18 Mar 2003 11:27:54 -0800
> To: <cocoa-dev...>
> Subject: cocoa-dev digest, Vol 2 #2089 - 10 msgs
>
> How often in the real life do we need loops of 500 000 iterations where
> every step allocates and deallocates ObjC instances?
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
I haven't been following this discussion to closely, but I really think
you'd gain more understanding of what your program is doing with the
memory it consumes if you used tools other than "top". I think "heap"
and ObjectAlloc are good starting points.
-- Dan
On Tuesday, March 18, 2003, at 10:35 PM, Lorenzo Puleo wrote:> Hi Oleg,_______________________________________________
> the problem is not the 500,000 iterations.
> I did that just to see better what was happening.
> Also the iterations could be 100,000 and the objects allocated could
> be 5
> per each iteration...
> The problem is that the unix "top" command in the Terminal tells me
> that the
> RSIZE of my application and the FREE memory don't come back to the
> initial
> values, after I have released the objects. So I would like to
> understand
> better what is happening.
>
>
> Best Regards
> --
> Lorenzo Puleo
> email: <archidea...>
>
>> From: <cocoa-dev-request...>
>> Reply-To: <cocoa-dev...>
>> Date: Tue, 18 Mar 2003 11:27:54 -0800
>> To: <cocoa-dev...>
>> Subject: cocoa-dev digest, Vol 2 #2089 - 10 msgs
>>
>> How often in the real life do we need loops of 500 000 iterations
>> where
>> every step allocates and deallocates ObjC instances?
> _______________________________________________
> cocoa-dev mailing list | <cocoa-dev...>
> Help/Unsubscribe/Archives:
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev
> Do not post admin requests to the list. They will be ignored.
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
I think you're running into a conceptual problem: the assumption that
your allocations and deallocations are atomically linked to the actual
memory allocation that the operating system is performing for your
program. Because C is so close to assembly language, we tend to think
of each call to malloc() and free() (or even [alloc] and [dealloc]) as
affecting the amount of heap that the process is currently allocated,
but this isn't necessarily true. There are a number of variables
involved: how much contiguous empty space there is in the heap, the way
that malloc determines the number of pages needed, whether the
implementation uses sbrk() or mmap(), etc.
There is, basically, no guarantee that when you finally [dealloc] an
object, the application reduces its memory footprint. This is often
actually a good thing, since you wouldn't want to release memory just
to allocate it again right away.
So, what can you do? Relax.
Since you're using a higher-level interface, other people (people who
have spent a lot of time profiling different allocation strategies) are
worrying about how much memory to take from the operating system. The
downside is that you're occasionally going to take more than you
actually need. The upside is that your responsibility is only to
manage the retain counts of your objects and let the runtime do the
rest.
What you need to watch for is growth; if your routine allocates 8
megabytes every time it runs, then you've got a memory leak. If after
exercising each portion of your program, your memory footprint is
stable, then you're doing fine.
Christian
On Tuesday, March 18, 2003, at 09:14 am, Lorenzo Puleo wrote:> Ok Bill, thank you,_______________________________________________
> but please what can I do now? How should I modify my code in order to
> use
> the memory properly? I am trying all the time, unsuccessfully. The unix
> "top" command tells me that Rsize and Free Mem never come back to the
> initial values.
> Should I still
> Best Regards
> --
> Lorenzo Puleo
> email: <archidea...>
> compact the heap like in Carbon?
>
>
> Best Regards
> --
> Lorenzo Puleo
> email: <archidea...>
>
>> From: Bill Bumgarner <bbum...>
>> Date: Tue, 18 Mar 2003 11:55:55 -0500
>> To: <cocoa-dev...>
>> Cc: Lorenzo Puleo <archidea...>, Phill Kelley
>> <pkelle2...>
>> Subject: Re: NSAutoreleasePool: how does it really work?
>>
>> On Tuesday, Mar 18, 2003, at 11:39 US/Eastern,
>> <cocoa-dev-request...> wrote:
>> ... analysis deleted ...
>>> - (IBAction)MyLoop:(id)sender
>>> {
>>> int i;
>>> xArray = [NSMutableArray array];
>>>
>>> for ( i = 0; i < 500000; i++ )
>>> {
>>> NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc]
>>> init];
>>> [xArray addObject:[NSString stringWithFormat: @"Don't leak,
>>> step
>>> %d", i]];
>>> [myPool release];
>>> }
>>> [xArray removeAllObjects];
>>> return;
>>> }
>>
>> The release pool in the above code doesn't actually do anything
>> (except
>> slowing down the code)!
>>
>> The @"..." format string is statically allocated; there should be
>> only
>> one.
>>
>> The string instance produced by -stringWithFormat: is autoreleased
>> into
>> myPool, by you shove it into an array inside of myPool's scope. This
>> ensures that the string is persisted beyond the call to -release on
>> myPool.
>>
>> If you were to remove the allocation of myPool, you will likely see a
>> reduction in the memory usage because of fewer object
>> creation/deletion
>> events to potentially fragment the heap.
>>
>> b.bum
> _______________________________________________
> cocoa-dev mailing list | <cocoa-dev...>
> Help/Unsubscribe/Archives:
> http://www.lists.apple.com/mailman/listinfo/cocoa-dev
> Do not post admin requests to the list. They will be ignored.
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored. -
Hi Christian,
Thank you. I am relaxed now. After the first MyLoop, if I run again the
routine, the memory doesn't grow anymore. So it's stable. At the first loop
my app memory really grows to 62MB.
Only I hope the other applications can use the memory that my application
doesn't use anymore. I would not like other application should be forced to
use virtual memory because my application memory has grown. But for this,
Bill already answered to this question. They can. See the following reply by
Bill.> After your loop has finished running and before you quit the app, the
> RSIZE doesn't decrease because there is no reason for it too! Mach
> will only decrease the RSIZE-- the resident working set of memory
> pages-- if some other application indicates that it needs to increase
> its RSIZE.
Thank you so much to you and to Bill.
Best Regards
--
Lorenzo Puleo
email: <archidea...>> From: Christian Longshore Claiborn <clc...>_______________________________________________
> Date: Tue, 18 Mar 2003 13:27:26 -0800
> To: Lorenzo Puleo <archidea...>
> Cc: <cocoa-dev...>
> Subject: Re: NSAutoreleasePool: how does it really work?
>
> What you need to watch for is growth; if your routine allocates 8
> megabytes every time it runs, then you've got a memory leak. If after
> exercising each portion of your program, your memory footprint is
> stable, then you're doing fine.
>
> Christian
cocoa-dev mailing list | <cocoa-dev...>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.


