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.
previous month march 2003 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today
MindNode
MindNode offered a free license !