CoreData huge memory usage - is this right ?

  • Hi - I'm in the process of writing code which will create and populate a CoreData SQLite store. I have a few million objects to deal with. I have written code which imports a text description of my data and then iterates through inserting and setting attributes of my CoreData objects. Things are going fine with the exception of one problem I am having... I am seeing CoreData take huge amounts of RAM to do it's thing. When my SQLite store is at around 10MB in size, my task is taking upwards of 500+MB of memory.

    I have run my application through 'Instruments' and the major culprit for all this memory usage is CoreData - namely the 'GeneralBlock-x' where x is a number. I am trying to track down this memory leak but I'm stuck as to where it is coming from. My code follows the standard template XCode code for a CoreData Application, and I am simply iterating through my object like this:

    while( not end of file )
    {
        id coreDataElement = [NSEntityDescription insertNewObjectForEntityForName:name in ManagedObjectContext:moc];

        // add my attributes for the element
        [coreDataElement setValue:value forKey:key];
        [coreDataElement setValue:value forKey:key];
        [coreDataElement setValue:value forKey:key];
        etc.

        [coreDataElement release];

        // then every 1000 entries or so I am saving the context

        [moc save:&error];

    }

    This code is executing fine, and my elements are indeed being inserted into the CoreData store because I have ran this code with an XML store and things are being stored fine. Saving of the moc is returning with no errors too.

    So I am stumped as to why CoreData is allocating an awful lot of memory for this task... can anyone shed some light on what I'm doing wrong ?

    Apologies if this is a trivial error - I am very new to CoreData.

    Thank you.
  • On Friday, December 14, 2007, at 12:39PM, "Martin Linklater" <mslinklater...> wrote:
    > Hi - I'm in the process of writing code which will create and populate a CoreData SQLite store. I have a few million objects to deal with. I have written code which imports a text description of my data and then iterates through inserting and setting attributes of my CoreData objects. Things are going fine with the exception of one problem I am having... I am seeing CoreData take huge amounts of RAM to do it's thing. When my SQLite store is at around 10MB in size, my task is taking upwards of 500+MB of memory.

      Hmm, do you have a lot of relationships ? Many to many relationships with inverses eats a lot of memory, because both collections are fetched in a simple addObject =/

    [ ... snip ... ]

    > This code is executing fine, and my elements are indeed being inserted into the CoreData store because I have ran this code with an XML store and things are being stored fine. Saving of the moc is returning with no errors too.
    >
    > So I am stumped as to why CoreData is allocating an awful lot of memory for this task... can anyone shed some light on what I'm doing wrong

      You can check the [NSManagedObjectContext setStalenessInterval:] documentation, disable the undoManager, read the http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles
    /cdMemory.html#//apple_ref/doc/uid/TP40001860
      and use a NSAutoreleasePool, even under GC (remember to use drain instead of release).

    :: marcelo.alves
  • > You can check the [NSManagedObjectContext setStalenessInterval:] documentation, disable the undoManager, read the http://developer.apple.com/documentation/Cocoa/Conceptual/CoreData/Articles
    /cdMemory.html#//apple_ref/doc/uid/TP40001860
      and use a NSAutoreleasePool, even under GC (remember to use drain instead of release).

      Winner. :-)

      Core Data or not, creating many objects in a tight loop (regardless
    of saving a file in the middle of it) never gives autoreleased objects
    a chance to be released. Since the
    -insertNewObjectForEntityForName:inManagedObjectContext: method
    returns an autoreleased object, the thousands of objects you're
    creating aren't going away until (likely) the end of your import.

      As suggested above, create an autorelease pool prior to entering
    your loop. Every thousand, you don't need to save, but you do need to
    -drain the pool. This will effectively cap the memory usage in the
    scenario you described.

    --
    I.S.
  • > Core Data or not, creating many objects in a tight loop (regardless
    > of saving a file in the middle of it) never gives autoreleased objects
    > a chance to be released. Since the
    > -insertNewObjectForEntityForName:inManagedObjectContext: method
    > returns an autoreleased object, the thousands of objects you're
    > creating aren't going away until (likely) the end of your import.
    >
    > As suggested above, create an autorelease pool prior to entering
    > your loop. Every thousand, you don't need to save, but you do need to
    > -drain the pool. This will effectively cap the memory usage in the
    > scenario you described.

    This doesn't seem to work... The memory usage isn't affected at all. My code now looks like this:

    import()
    {
    NSAutoreleasePool* subPool = [[NSAutoreleasePool alloc] init];

    while( not end of file )
    {
        id coreDataElement = [NSEntityDescription insertNewObjectForEntityForName:name in ManagedObjectContext:moc];

        // add my attributes for the element
        [coreDataElement setValue:value forKey:key];
        [coreDataElement setValue:value forKey:key];
        [coreDataElement setValue:value forKey:key];
        etc.

        [coreDataElement release];

        // then every 1000 entries or so I am saving the context
        {
            [moc save:&error];
            [subPool drain];
        }

    }

    [subPool drain];

    return;
    }
  • [ .... snip ....]

    > This doesn't seem to work... The memory usage isn't affected at all. My code now looks like this:

      Use a low value (but greater than zero) in setStalenessInterval and disable the UndoManager, before the loop. Your MOC has a reference to every object created.

    >
    > import()
    > {
    > NSAutoreleasePool* subPool = [[NSAutoreleasePool alloc] init];
    >
    > while( not end of file )
    > {
    > id coreDataElement = [NSEntityDescription insertNewObjectForEntityForName:name in ManagedObjectContext:moc];
    >
    > // add my attributes for the element
    > [coreDataElement setValue:value forKey:key];
    > [coreDataElement setValue:value forKey:key];
    > [coreDataElement setValue:value forKey:key];
    > etc.
    >
    > [coreDataElement release];
    >
    > // then every 1000 entries or so I am saving the context
    > {
    > [moc save:&error];
    > [subPool drain];
    > }
    >
    > }
    >
    > [subPool drain];
    >
    > return;
    > }
  • On Friday, December 14, 2007, at 03:25PM, <marcelo.alves...> wrote:
    >
    > [ .... snip ....]
    >
    >> This doesn't seem to work... The memory usage isn't affected at all. My code now looks like this:
    >
    > Use a low value (but greater than zero) in setStalenessInterval and disable the UndoManager, before the loop. Your MOC has a reference to every object created.

    OK I have set my staleness interval to 10.0

    (newbie Q) - Err, how do I disable the undo manager again ?

    Thanks.
  • On Friday, December 14, 2007, at 03:31PM, "Martin Linklater" <mslinklater...> wrote:
    >
    > On Friday, December 14, 2007, at 03:25PM, <marcelo.alves...>  wrote:
    >>
    >> [ .... snip ....]
    >>
    >>> This doesn't seem to work... The memory usage isn't affected at all. My code now looks like this:
    >>
    >> Use a low value (but greater than zero) in setStalenessInterval and disable the UndoManager, before the loop. Your MOC has a reference to every object created.
    >

    That's it - seems to be working fine now.

    Thank you very much for your advice.


    >
    >
  • Following up on my earlier thread I have cleaned up a lot of my own memory leaks but I am still seeing CoreData take a lot of memory up. By the time my application has imported around 500,000 entries my application memory usage is over 2GB and my machine starts to crawl. At this point the SQLite store that I'm actually creating is around 20MB in size.

    When I run my application through 'Instruments' and get it to trace Object Allocations I'm seeing a lot of memory (over 50% of total) being used by Core Data - at the [NSManagedObjectContext save:] method. This memory use just keeps growing and growing as my application executes.

    I have disabled undo during import and I have set the stalenessInterval to 1.0. I have my own NSAutoreleasePool which gets drained every 1000 entries.

    I must still be doing something silly - anyone got any ideas ?

    Thank you.
  • > I must still be doing something silly - anyone got any ideas ?

      Perhaps if you'd post your import routine?

    --
    I.S.
  • Hi Martin,

    I have noticed that it is good practice not to save too many MO's in
    one save: operation (max 10,000 or so). What you can do is start
    inserting the objects in one MOC, save this MOC in a separate thread
    and start inserting in a new MOC concurrently (make sure you don't
    have dependencies between the objects in the (unsaved) MOCs).

    - Diederik

    --
    Diederik Hoogenboom
    AIM: obviousmatter
    Twitter: obviousmatter

    Obvious Matter - DiskLibrary for Mac
    http://www.obviousmatter.com

    On 17 dec 2007, at 15:25, Martin Linklater wrote:

    > Following up on my earlier thread I have cleaned up a lot of my own
    > memory leaks but I am still seeing CoreData take a lot of memory up.
    > By the time my application has imported around 500,000 entries my
    > application memory usage is over 2GB and my machine starts to crawl.
    > At this point the SQLite store that I'm actually creating is around
    > 20MB in size.
    >
    > When I run my application through 'Instruments' and get it to trace
    > Object Allocations I'm seeing a lot of memory (over 50% of total)
    > being used by Core Data - at the [NSManagedObjectContext save:]
    > method. This memory use just keeps growing and growing as my
    > application executes.
    >
    > I have disabled undo during import and I have set the
    > stalenessInterval to 1.0. I have my own NSAutoreleasePool which gets
    > drained every 1000 entries.
    >
    > I must still be doing something silly - anyone got any ideas ?
    >
    > Thank you.
    >
  • > Perhaps if you'd post your import routine?

    Of course... Here are the relevant parts of my code:

    Main Controller:
    {
    NSManagedObjectContext *moc = [appDelegate managedObjectContext];

    [moc setStalenessInterval:0.1];
    [[moc undoManager] disableUndoRegistration];

    [importer importFile:@"AgtOfferDetails.sql"
    usingEntity:@"AgtOfferDetails" andFlags:0];
    lots more import calls (around 100) etc.

    [[moc undoManager] enableUndoRegistration];
    }

    Import routine:

    - (void)importFile:(NSString*)file usingEntity:(NSString*)entity
    andFlags:(int)flagsIn;
    {
    int entryNum = 0;

    NSAutoreleasePool* subPool = [[NSAutoreleasePool alloc] init];

    while( thisEntry = [filePartsEnum nextObject] )
    {
      entryNum++;

      id coreDataElement = [NSEntityDescription
    insertNewObjectForEntityForName:entity inManagedObjectContext:[self
    moc]];

      // set attributes
            [coreDataElement setValue:[NSNumber numberWithInt:[valueString
    intValue]] forKey:keyString];
      ..etc...

      if( ( entryNum % 1000 ) == 0)
      [subPool drain];
      }
    }

      BOOL ret = [moc save:&error];

    if( ret == NO )
    {
      CPSLogInfo( thisEntry );
      [[NSApplication sharedApplication] presentError:error];
    }

    [subPool release];
    }

    Sorry for the delay - .Mac was evperiencing problems yesterday ad I
    was unable to receive or send email.

    Thanks.
  • On 18 Dec 2007, at 10:57, Martin Linklater wrote:

    >> Perhaps if you'd post your import routine?
    >
    > Of course... Here are the relevant parts of my code:
    >
    > Main Controller:
    > {
    > NSManagedObjectContext *moc = [appDelegate managedObjectContext];
    >
    > [moc setStalenessInterval:0.1];
    > [[moc undoManager] disableUndoRegistration];
    >
    > [importer importFile:@"AgtOfferDetails.sql"
    > usingEntity:@"AgtOfferDetails" andFlags:0];
    > lots more import calls (around 100) etc.
    >
    > [[moc undoManager] enableUndoRegistration];
    > }

    The above code for the undo manager will probably not work as you're
    expecting. Before the disableUndoRegistration and
    enableUndoRegistration methods, you need to call [moc
    processPendingChanges]
  • Hi,

    I posted similar problems here a few weeks back, but nothing really
    helped (at least on Leopard) until I simply reset the context.

    My "tight" loop now ends with a

    [context save: &error];
    [context reset];
    [pool release];

    every few thousand inserts. This isn't great because it invalidates
    all references for the context, so you need to keep track of the
    object ids if you need to get an object back into the context after
    the reset, but my memory usage is now down to nothing.

    I'm not a great expert on CoreData but I suspect that the Leopard
    implementation in non-garbage collected mode doesn't release newly
    created managed objects properly until you reset the context. I tried
    to disable the undo manager as suggested earlier in this thread but
    that made no difference.. I didn't file a bug with Apple because I
    just don't know enough about CoreData to be definite about it, but my
    workaround works just fine.

    I hope this helps.

    Best regards,

    Frank

    On 14 Dec 2007, at 15:38, Martin Linklater wrote:

    > Hi - I'm in the process of writing code which will create and
    > populate a CoreData SQLite store. I have a few million objects to
    > deal with. I have written code which imports a text description of
    > my data and then iterates through inserting and setting attributes
    > of my CoreData objects. Things are going fine with the exception of
    > one problem I am having... I am seeing CoreData take huge amounts of
    > RAM to do it's thing. When my SQLite store is at around 10MB in
    > size, my task is taking upwards of 500+MB of memory.
    >
    > I have run my application through 'Instruments' and the major
    > culprit for all this memory usage is CoreData - namely the
    > 'GeneralBlock-x' where x is a number. I am trying to track down this
    > memory leak but I'm stuck as to where it is coming from. My code
    > follows the standard template XCode code for a CoreData Application,
    > and I am simply iterating through my object like this:
    >
    > while( not end of file )
    > {
    > id coreDataElement = [NSEntityDescription
    > insertNewObjectForEntityForName:name in ManagedObjectContext:moc];
    >
    > // add my attributes for the element
    > [coreDataElement setValue:value forKey:key];
    > [coreDataElement setValue:value forKey:key];
    > [coreDataElement setValue:value forKey:key];
    > etc.
    >
    > [coreDataElement release];
    >
    > // then every 1000 entries or so I am saving the context
    >
    > [moc save:&error];
    >
    > }
    >
    > This code is executing fine, and my elements are indeed being
    > inserted into the CoreData store because I have ran this code with
    > an XML store and things are being stored fine. Saving of the moc is
    > returning with no errors too.
    >
    > So I am stumped as to why CoreData is allocating an awful lot of
    > memory for this task... can anyone shed some light on what I'm doing
    > wrong ?
    >
    > Apologies if this is a trivial error - I am very new to CoreData.
    >
    > Thank you.
  • Thanks for the suggestions. I've got it working by resetting the
    context every 1000 entries and the magic ingredient seems to be to set
    Garbage Collection as Required.

    This must be a bug - surely ? Core Data with GC disabled seems to leak
    tons of memory. Anyone from the Core Data team got anything to say ?

    Thanks again for all your suggestions everyone.

    On 18 Dec 2007, at 11:37, Frank Reiff wrote:

    > Hi,
    >
    > I posted similar problems here a few weeks back, but nothing really
    > helped (at least on Leopard) until I simply reset the context.
    >
    > My "tight" loop now ends with a
    >
    > [context save: &error];
    > [context reset];
    > [pool release];
    >
    > every few thousand inserts. This isn't great because it invalidates
    > all references for the context, so you need to keep track of the
    > object ids if you need to get an object back into the context after
    > the reset, but my memory usage is now down to nothing.
    >
    > I'm not a great expert on CoreData but I suspect that the Leopard
    > implementation in non-garbage collected mode doesn't release newly
    > created managed objects properly until you reset the context. I
    > tried to disable the undo manager as suggested earlier in this
    > thread but that made no difference.. I didn't file a bug with Apple
    > because I just don't know enough about CoreData to be definite about
    > it, but my workaround works just fine.
    >
    > I hope this helps.
    >
    > Best regards,
    >
    > Frank
    >
    >
    > On 14 Dec 2007, at 15:38, Martin Linklater wrote:
    >
    >> Hi - I'm in the process of writing code which will create and
    >> populate a CoreData SQLite store. I have a few million objects to
    >> deal with. I have written code which imports a text description of
    >> my data and then iterates through inserting and setting attributes
    >> of my CoreData objects. Things are going fine with the exception of
    >> one problem I am having... I am seeing CoreData take huge amounts
    >> of RAM to do it's thing. When my SQLite store is at around 10MB in
    >> size, my task is taking upwards of 500+MB of memory.
    >>
    >> I have run my application through 'Instruments' and the major
    >> culprit for all this memory usage is CoreData - namely the
    >> 'GeneralBlock-x' where x is a number. I am trying to track down
    >> this memory leak but I'm stuck as to where it is coming from. My
    >> code follows the standard template XCode code for a CoreData
    >> Application, and I am simply iterating through my object like this:
    >>
    >> while( not end of file )
    >> {
    >> id coreDataElement = [NSEntityDescription
    >> insertNewObjectForEntityForName:name in ManagedObjectContext:moc];
    >>
    >> // add my attributes for the element
    >> [coreDataElement setValue:value forKey:key];
    >> [coreDataElement setValue:value forKey:key];
    >> [coreDataElement setValue:value forKey:key];
    >> etc.
    >>
    >> [coreDataElement release];
    >>
    >> // then every 1000 entries or so I am saving the context
    >>
    >> [moc save:&error];
    >>
    >> }
    >>
    >> This code is executing fine, and my elements are indeed being
    >> inserted into the CoreData store because I have ran this code with
    >> an XML store and things are being stored fine. Saving of the moc is
    >> returning with no errors too.
    >>
    >> So I am stumped as to why CoreData is allocating an awful lot of
    >> memory for this task... can anyone shed some light on what I'm
    >> doing wrong ?
    >>
    >> Apologies if this is a trivial error - I am very new to CoreData.
    >>
    >> Thank you.
    >
  • Martin,

    We recommend an import use its own MOC, and simply set the undo
    manager on the MOC to nil.  Easier, better, less filling.

    The staleness interval has nothing to do with imports.  It affects
    the, well, staleness of cached data for faulting.

    It's insufficient to drain the autorelease pool every 1000
    iterations.  You need to actually save the MOC, then drain the pool.
    Until you save, the MOC needs to retain all the pending changes you've
    made to the inserted objects.  Losing changes just because somebody
    popped an autorelease pool would be bad.  This is documented in
    several places, including the programming guide and -
    setRetainsRegisteredObject:

    There is an additional issue that complicates matters greatly under
    the retain/release (not GC) memory model.  Managed objects with
    relationships nearly always create unreclaimable retain cycles.

    Example:

    Department <->> People

    Department has a relationship to many people, and each person has an
    inverse relationship to the department.  Since these objects retain
    each other, the retain game is over.  This is a fundamental limitation
    to retain counting.

    To help alleviate this, Core Data allows you to turn a managed object
    back into a fault.  You can turn a specific object back into a fault
    with -refreshObject:mergeChanges:NO (which shouldn't be called on a
    managed object with unsaved changes pending).  Or you can use the
    sledge hammer, and just -reset the whole context.  A big but not quite
    that big hammer would be to call -registeredObjects on the MOC you
    just saved, and then for (NSManagedObject* mo in registeredObjects)
    { [moc refreshObject:mo mergeChanges:NO] }  This is a bit like reset,
    but you can still re-use the managed objects themselves in the future.

    As for why can't Core Data break the retain cycles for the objects you
    no longer want (i.e. like -reset, but not everything), how would we
    know ?  We can't tell the difference between your UI/array controller/
    whatever retaining an object, and an inverse relationship retaining
    the object.  It's trivial enough for you to grab the -
    registeredObjects set, make a mutable copy, remove the objects you
    want to preserve, and refresh the rest.  And if you can't tell the
    difference between the objects you want to preserve and those you want
    to nuke, how could we ?

    If you have concrete ideas for an API that would make this easier,
    please file an enhancement request at bugreport.apple.com

    The only meaningful difference between -reset and -release on the MOC
    is whether or not you ever need to use that MOC object again.  And,
    now under GC, -reset is more immediate.

    It may occur to some to ask why turning the object back into a fault
    helps.  Faults represent futures for unrealized/unmaterialized pieces
    of a graph of connected objects.  They don't retain anything as they
    have no data, just an identity.  A managed object that's in use has
    data, and retains that data much in the same way any Cocoa object's
    standard setter methods might work.  The active pieces of the graph
    are wired down, and the periphery are faults.  Like a cloud.  If you
    turn enough of the center pieces of the cloud back into faults, you'll
    have multiple distinct clouds instead (which is usually better)

    MOC are not particularly expensive to create, so if you cache your
    PSC, you can use different MOCs for different working sets or distinct
    operations.

    I can import millions of records in a stable 3MB of memory without
    calling -reset.

    - Ben
  • >

    Thanks for your response Ben. It seems I need a lot more experience
    with Core Data before I fully understand it 8). Your input is much
    appreciated.

    - Martin
  • On Dec 18, 2007, at 5:46 PM, Ben Trumbull wrote:

    > Martin,
    >
    > We recommend an import use its own MOC, and simply set the undo
    > manager on the MOC to nil.  Easier, better, less filling.

    > MOC are not particularly expensive to create, so if you cache your
    > PSC, you can use different MOCs for different working sets or
    > distinct operations.

    Just to be very clear, Ben:  I read this to mean that it's fine to
    have multiple MOC's in one thread for a given PSC.  Right?  MOCs
    should not be shared across multiple threads (per documentation), but
    I gather that the converse is false.

    Hal
  • Dear Ben,

    Thanks for the comprehensive answer. It's nice to get a full
    explanation from somebody who is in the know.

    As a former full-time framework developer, I fully understand why you
    are a bit defensive about the documentation (It's all in there!!):
    there's always somebody complaining who has obviously not read it
    properly and how can anybody expect to do anything this complicated
    without taking the trouble of reading the documentation? Been there,
    done that, bought the T-shirt.

    On the other hand, when you have something as complicated as Core
    Data, the documentation is almost as important as the framework
    itself. Apple's documentation in general is high on specifics and low
    on the "big picture" stuff. (I just wasted a day trying to get an
    NSBrowser to work with bindings and then I'm off trying to figure out
    how to resize an NSSplitView). Each method is documented just fine,
    but how they interact and what role they play in the overall design of
    the functionality is usually at best touched upon in the class
    documentation.

    There is a "big picture" documentation for Core Data and it does a
    better job than much of the AppKit (NSBrowser, etc.) documentation,
    but to be honest it's still far from great. As this import/ memory
    leak question seems to come up a lot, it might be worth putting your
    explanation into the Core Data FAQ and perhaps even making some sample
    code available for it.

    A great example of good documentation for a framework just like this
    is Hibernate's manual (http://www.hibernate.org/), which does a great
    job of demonstrating functionality by example and discussing the
    design decisions in some detail.

    The classical object graph retaining problem that you describe IMHO is
    a fundamental weakness of the Core Data framework. I'm sure you've got
    sound technical reasons for putting so much emphasis on inverse
    relationships even where they don't make sense, but in practice they
    are awkward to use. It's the age old question of whether your object-
    relational mapping tool should be more "relational" or more "object"-
    oriented. In my personal opinion, it's too "relational" when it
    refuses to support ordered collection directly and it's too "object"-
    oriented when it forces (ok, strongly recommends that) you to define
    inverse relationships.

    That's just my 5 euro-cents of feedback. I'm a happy Core Data user
    and the new enhancements for Leopard rock.

    Keep up the good work.

    Best regards,

    Frank

    On 19 Dec 2007, at 02:46, Ben Trumbull wrote:

    > Martin,
    >
    > We recommend an import use its own MOC, and simply set the undo
    > manager on the MOC to nil.  Easier, better, less filling.
    >
    > The staleness interval has nothing to do with imports.  It affects
    > the, well, staleness of cached data for faulting.
    >
    > It's insufficient to drain the autorelease pool every 1000
    > iterations.  You need to actually save the MOC, then drain the
    > pool.  Until you save, the MOC needs to retain all the pending
    > changes you've made to the inserted objects.  Losing changes just
    > because somebody popped an autorelease pool would be bad.  This is
    > documented in several places, including the programming guide and -
    > setRetainsRegisteredObject:
    >
    > There is an additional issue that complicates matters greatly under
    > the retain/release (not GC) memory model.  Managed objects with
    > relationships nearly always create unreclaimable retain cycles.
    >
    > Example:
    >
    > Department <->> People
    >
    > Department has a relationship to many people, and each person has an
    > inverse relationship to the department.  Since these objects retain
    > each other, the retain game is over.  This is a fundamental
    > limitation to retain counting.
    >
    > To help alleviate this, Core Data allows you to turn a managed
    > object back into a fault.  You can turn a specific object back into
    > a fault with -refreshObject:mergeChanges:NO (which shouldn't be
    > called on a managed object with unsaved changes pending).  Or you
    > can use the sledge hammer, and just -reset the whole context.  A big
    > but not quite that big hammer would be to call -registeredObjects on
    > the MOC you just saved, and then for (NSManagedObject* mo in
    > registeredObjects) { [moc refreshObject:mo mergeChanges:NO] }  This
    > is a bit like reset, but you can still re-use the managed objects
    > themselves in the future.
    >
    > As for why can't Core Data break the retain cycles for the objects
    > you no longer want (i.e. like -reset, but not everything), how would
    > we know ?  We can't tell the difference between your UI/array
    > controller/whatever retaining an object, and an inverse relationship
    > retaining the object.  It's trivial enough for you to grab the -
    > registeredObjects set, make a mutable copy, remove the objects you
    > want to preserve, and refresh the rest.  And if you can't tell the
    > difference between the objects you want to preserve and those you
    > want to nuke, how could we ?
    >
    > If you have concrete ideas for an API that would make this easier,
    > please file an enhancement request at bugreport.apple.com
    >
    > The only meaningful difference between -reset and -release on the
    > MOC is whether or not you ever need to use that MOC object again.
    > And, now under GC, -reset is more immediate.
    >
    > It may occur to some to ask why turning the object back into a fault
    > helps.  Faults represent futures for unrealized/unmaterialized
    > pieces of a graph of connected objects.  They don't retain anything
    > as they have no data, just an identity.  A managed object that's in
    > use has data, and retains that data much in the same way any Cocoa
    > object's standard setter methods might work.  The active pieces of
    > the graph are wired down, and the periphery are faults.  Like a
    > cloud.  If you turn enough of the center pieces of the cloud back
    > into faults, you'll have multiple distinct clouds instead (which is
    > usually better)
    >
    > MOC are not particularly expensive to create, so if you cache your
    > PSC, you can use different MOCs for different working sets or
    > distinct operations.
    >
    > I can import millions of records in a stable 3MB of memory without
    > calling -reset.
    >
    > - Ben
  • At 7:21 AM -0800 12/19/07, <cocoa-dev-request...> wrote:
    >> MOC are not particularly expensive to create, so if you cache your
    >> PSC, you can use different MOCs for different working sets or
    >> distinct operations.
    >
    > Just to be very clear, Ben:  I read this to mean that it's fine to
    > have multiple MOC's in one thread for a given PSC.  Right?  MOCs
    > should not be shared across multiple threads (per documentation), but
    > I gather that the converse is false.

    Absolutely.  You can use as many MOCs per PSC as you like, but life
    is best if a MOC is only used by the thread that created it.

    One might diagram a PSC <->> MOC relationship, a process <->> PSC
    relationship, and a thread <->> MOC relationship.

    It is technically possible to share a MOC between threads, but this
    requires manually locking the MOC, and I haven't seen any decent
    examples where a developer was sufficiently rewarded for the effort.

    Sharing a PSC between threads also requires manual locking, but this
    is pretty easy, and directly messaging the PSC is rare (compared to
    working with MOs and MOCs)

    ADC has available for download the 10.5 debug libraries and
    frameworks, which enforce our threading expectations with assertions.
    --

    -Ben
previous month december 2007 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