Re: Avoiding mutual retain cycles
On Jul 22, 2008, at 11:52 , Philippe Mougin wrote: Le 22 juil. 08 à 06:21, Marcel Weiher a écrit : http://portal.acm.org/citation.cfm?id=1035292.1028982 There are also interesting bits in their conclusion: "This explains why highly optimized tracing and reference counting collectors have surprisingly similar performance characteristics. In the process we discovered some interesting things: a write barrier is fundamentally a feature of reference counting; and the existence of cycles is what makes garbage collection inherently non- incremental: cycle collection is “trace-like”." Yes, it is a very interesting read, as are some of the related articles that describe cycle-collectors. Of course, in Objective-C, one must keep in mind that while they share some "deep structure", the reference counting model we have is manual whereas the tracing collector is automatic. Semi-manual, yes. However, the "automation" axis is actually distinct from the "tracing vs refcounting" axis, which is something that is often misrepresented (not that you did): a distinction is made between "reference counting" and "GC". This distinction is not valid, both refcounting and tracing are forms of GC, there is no "in- principle" difference in capabilities, just choices made by specific implementations. To illustrate, I automated my reference counting a long time ago, through both coding-practices and actual code: 1. Only use accessors to set ivars (in general: to access), including during object creation [coding practice)] 2. Automate accessor generation ( accessor-macros in my case, @properties have a similar effect) [code] Those two elements largely eliminated reference counting from my code- base, meaning that code generally looks the same as it would with a (tracing) GC. There are only 2 elements left: the -dealloc method and cyclic references, with the latter being the original subject of this thread. I actually also addressed those two, at least in specialized circumstances, through some more code: 3. Automate the '-release' messages sent from -dealloc via some introspection [code] 4. Build a cycle collector [code] With those two additional elements in place, the RC implementation becomes completely equivalent in functionality and convenience to a tracing collector, with the differences now implementation choices that affect such things as performance profiles and malleability. I actually don't use 3+4 in most of my code (4 being part of my Postscript interpreter), but they do show that the theoretical equivalence given in the paper is not just a theoretical result, but a practical option. It just turned out that neither dealloc methods nor cyclic references were enough of a problem for me in the general case in order to invest more time in 3+4. But this was a purely pragmatic choice, not an in-principle limitation. Cheers, Marcel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
Le 22 juil. 08 à 06:21, Marcel Weiher a écrit : On Jul 21, 2008, at 13:03 , Philippe Mougin wrote: Le 21 juil. 08 à 20:50, Markus Spoettl a écrit : I'm wondering if there is a general rule or mechanism that suggests what to do in such a case. For instance, how are delegates implemented in AppKit, are they retained? If so, when are they released. It can't be in -dealloc, otherwise everything would lock itself out of deallocation? In the general case, there is no rule or mechanism to deal with retain cycles other than implementing something equivalent to a garbage collector. In some situations, however, the specific semantics and life-cycle of the objects you are dealing with allow implementing more simpler, ad hoc solutions (e.g., ownership management in the view hierarchy). Still, this requires notable housekeeping efforts and is often error prone. If you are in a situation where you can make use of Cocoa's garbage collector, you should go for it. It will free you from a bunch of low-level memory management tasks, including having to care about cyclic references. http://portal.acm.org/citation.cfm?id=1035292.1028982 "Tracing and reference counting are uniformly viewed as being fundamentally different approaches to garbage collection that possess very distinct performance properties. We have implemented high-performance collectors of both types, and in the process observed that the more we optimized them, the more similarly they behaved - that they seem to share some deep structure. We present a formulation of the two algorithms that shows that they are in fact duals of each other. Intuitively, the difference is that tracing operates on live objects, or "matter", while reference counting operates on dead objects, or "anti-matter". For every operation performed by the tracing collector, there is a precisely corresponding anti-operation performed by the reference counting collector. Using this framework, we show that all high-performance collectors (for example, deferred reference counting and generational collection) are in fact hybrids of tracing and reference counting. We develop a uniform cost-model for the collectors to quantify the trade-offs that result from choosing different hybridizations of tracing and reference counting. This allows the correct scheme to be selected based on system performance requirements and the expected properties of the target application." Well said! There are also interesting bits in their conclusion: "This explains why highly optimized tracing and reference counting collectors have surprisingly similar performance characteristics. In the process we discovered some interesting things: a write barrier is fundamentally a feature of reference counting; and the existence of cycles is what makes garbage collection inherently non-incremental: cycle collection is “trace-like”." Of course, in Objective-C, one must keep in mind that while they share some "deep structure", the reference counting model we have is manual whereas the tracing collector is automatic. Philippe Mougin ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 11:20 PM, Quincey Morris wrote: Call me a retro coward, but I absolutely dislike the idea of GC. I just don't see the point of it given the complicated implications it can have. But I hope you do see the irony of that last statement, in the context of this thread. I knew this would backfire when I wrote it. What I meant to say was that you give up a lot of control over the inner workings of your application with GC and I don't like that idea too much. Just don't. Anyway, it's great to have choices, so everyone can use what they think suits them best. Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 20:27, Markus Spoettl wrote: Call me a retro coward, but I absolutely dislike the idea of GC. I just don't see the point of it given the complicated implications it can have. But I hope you do see the irony of that last statement, in the context of this thread. FWIW, I have nothing bad to say about writing non-gc apps, or about anyone who writes non-gc apps, except that you couldn't pay me to go back to doing it. :) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 13:03 , Philippe Mougin wrote: Le 21 juil. 08 à 20:50, Markus Spoettl a écrit : I'm wondering if there is a general rule or mechanism that suggests what to do in such a case. For instance, how are delegates implemented in AppKit, are they retained? If so, when are they released. It can't be in -dealloc, otherwise everything would lock itself out of deallocation? In the general case, there is no rule or mechanism to deal with retain cycles other than implementing something equivalent to a garbage collector. In some situations, however, the specific semantics and life-cycle of the objects you are dealing with allow implementing more simpler, ad hoc solutions (e.g., ownership management in the view hierarchy). Still, this requires notable housekeeping efforts and is often error prone. If you are in a situation where you can make use of Cocoa's garbage collector, you should go for it. It will free you from a bunch of low-level memory management tasks, including having to care about cyclic references. http://portal.acm.org/citation.cfm?id=1035292.1028982 "Tracing and reference counting are uniformly viewed as being fundamentally different approaches to garbage collection that possess very distinct performance properties. We have implemented high- performance collectors of both types, and in the process observed that the more we optimized them, the more similarly they behaved - that they seem to share some deep structure. We present a formulation of the two algorithms that shows that they are in fact duals of each other. Intuitively, the difference is that tracing operates on live objects, or "matter", while reference counting operates on dead objects, or "anti-matter". For every operation performed by the tracing collector, there is a precisely corresponding anti-operation performed by the reference counting collector. Using this framework, we show that all high-performance collectors (for example, deferred reference counting and generational collection) are in fact hybrids of tracing and reference counting. We develop a uniform cost-model for the collectors to quantify the trade-offs that result from choosing different hybridizations of tracing and reference counting. This allows the correct scheme to be selected based on system performance requirements and the expected properties of the target application." ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 7:49 PM, Andreas Mayer wrote: I don't know why you'd think the collection view might own the item's view. You set the view for the view item, so the hierarchy seems to be quite clear. (The collection view *might* retain the view too. That's an implementation detail.) Well that's exactly what is important here, isn't it. How would you get a retain cycle here? You just hold on to the collection view. Everything else should not be your responsibility. Unless you have to have access to the collection view or the view's item controller. If you set something, it's usually retained. Exceptions from this norm should certainly be documented - like it is with delegates. That basically answers the original question I had, but things can get complicated and details become important. Regards Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Mon, Jul 21, 2008 at 11:24 PM, Markus Spoettl <[EMAIL PROTECTED]> wrote: > On Jul 21, 2008, at 7:23 PM, Michael Ash wrote: >> >> Without investigating things more deeply, just from the basic stuff I >> know about the classes in question, I'd assume that the >> NSCollectionView owns the NSCollectionViewItems and the views, and the >> NSCollectionViewItems would also own the views. Where is the retain >> cycle? > > > Well there is none in the default setup, of course. But here's a non > far-fetched example to easily create one. > > If you're implementing a custom NSView that for some reason has to have > access to the NSCollectionViewItem or NSCollectionView it belongs to, the > only proper way to do so (in the collection view world) is by accessing the > NSCollectionViewItem which has a -collectionView method that returns the > collection view. > > So you need a way back and this you do with a pointer to the > NSCollectionViewItem in a suitable place. As you don't know the ownership > circumstances of NSCollectionViewItem and its view the safest thing to do is > to retain the NSCollectionViewItem in the view. There's the retain cycle, > because - as it turns out - the NSCollectionViewItem seems to retain the > view. > > The point of all this is not that it's avoided easily - which it is. The > point is that you can't know the circumstances unless it's documented and > the original question was how AppKit does avoid things like that. I guess I misunderstood, I thought you meant that there was already a cycle there, or at least that it appeared to have one. I agree that it's not necessarily immediately obvious. But if you think about it, it should become clear. The NSCollectionViewItem has to stick around somehow, so that things can access its representedObject, use it as a target for controls, etc. Therefore something in there has to be hanging onto it already, which means you don't have to (and probably shouldn't, because you might make a cycle, as you've seen). So it does require some thought, but I believe the necessary information is there if you dig. > Now that I read more on retain cycles it's clear there is no ingenious Cocoa > solution to this problem, just plain old defensive programming techniques - > which is what I was wondering about. Well, clearly defined ownership helps a lot, but you're right, there's no special sauce to fix it. Mike ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
Am 21.07.2008 um 22:02 Uhr schrieb Markus Spoettl: For example NSCollectionView, NSCollectionViewItem and its view. One may or may not suspect the NSCollectionViewItem owns the corresponding view. It may as well not own it and instead the NSCollectionView owns both. I don't know why you'd think the collection view might own the item's view. You set the view for the view item, so the hierarchy seems to be quite clear. (The collection view *might* retain the view too. That's an implementation detail.) Of course once you run into a retain cycle problem with this and no NSCollectionViewItem ever gets released because of it (like I did) you quickly learn why and who owns the view. How would you get a retain cycle here? You just hold on to the collection view. Everything else should not be your responsibility. I have to point out that I did not actually use those classes yet. (Instead I built something similar myself for 10.4. compatibility.) So I might be wrong here; I'd be surprised though. The point is, unless this is documented explicitly the ownership relations are not clear all the time. If you set something, it's usually retained. Exceptions from this norm should certainly be documented - like it is with delegates. Andreas ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 1:03 PM, Philippe Mougin wrote: In the general case, there is no rule or mechanism to deal with retain cycles other than implementing something equivalent to a garbage collector. In some situations, however, the specific semantics and life-cycle of the objects you are dealing with allow implementing more simpler, ad hoc solutions (e.g., ownership management in the view hierarchy). Still, this requires notable housekeeping efforts and is often error prone. If you are in a situation where you can make use of Cocoa's garbage collector, you should go for it. It will free you from a bunch of low-level memory management tasks, including having to care about cyclic references. Call me a retro coward, but I absolutely dislike the idea of GC. I just don't see the point of it given the complicated implications it can have. Anyway, thanks for your suggestion. Regards Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 7:23 PM, Michael Ash wrote: Without investigating things more deeply, just from the basic stuff I know about the classes in question, I'd assume that the NSCollectionView owns the NSCollectionViewItems and the views, and the NSCollectionViewItems would also own the views. Where is the retain cycle? Well there is none in the default setup, of course. But here's a non far-fetched example to easily create one. If you're implementing a custom NSView that for some reason has to have access to the NSCollectionViewItem or NSCollectionView it belongs to, the only proper way to do so (in the collection view world) is by accessing the NSCollectionViewItem which has a -collectionView method that returns the collection view. So you need a way back and this you do with a pointer to the NSCollectionViewItem in a suitable place. As you don't know the ownership circumstances of NSCollectionViewItem and its view the safest thing to do is to retain the NSCollectionViewItem in the view. There's the retain cycle, because - as it turns out - the NSCollectionViewItem seems to retain the view. The point of all this is not that it's avoided easily - which it is. The point is that you can't know the circumstances unless it's documented and the original question was how AppKit does avoid things like that. Now that I read more on retain cycles it's clear there is no ingenious Cocoa solution to this problem, just plain old defensive programming techniques - which is what I was wondering about. Regards Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Mon, Jul 21, 2008 at 4:02 PM, Markus Spoettl <[EMAIL PROTECTED]> wrote: >>> But there are still cases where it is unknown which of the objects is >>> going to be released first >> >> Care to name one? > > For example NSCollectionView, NSCollectionViewItem and its view. One may or > may not suspect the NSCollectionViewItem owns the corresponding view. It may > as well not own it and instead the NSCollectionView owns both. Of course > once you run into a retain cycle problem with this and no > NSCollectionViewItem ever gets released because of it (like I did) you > quickly learn why and who owns the view. Without investigating things more deeply, just from the basic stuff I know about the classes in question, I'd assume that the NSCollectionView owns the NSCollectionViewItems and the views, and the NSCollectionViewItems would also own the views. Where is the retain cycle? Mike ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
Le 21 juil. 08 à 20:50, Markus Spoettl a écrit : [...] I'm wondering if there is a general rule or mechanism that suggests what to do in such a case. For instance, how are delegates implemented in AppKit, are they retained? If so, when are they released. It can't be in -dealloc, otherwise everything would lock itself out of deallocation? Thoughts? In the general case, there is no rule or mechanism to deal with retain cycles other than implementing something equivalent to a garbage collector. In some situations, however, the specific semantics and life-cycle of the objects you are dealing with allow implementing more simpler, ad hoc solutions (e.g., ownership management in the view hierarchy). Still, this requires notable housekeeping efforts and is often error prone. If you are in a situation where you can make use of Cocoa's garbage collector, you should go for it. It will free you from a bunch of low-level memory management tasks, including having to care about cyclic references. Philippe Mougin http://www.fscript.org ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 12:28 PM, Ken Thomases wrote: Actually, it is not against the guidelines, it is in keeping with them. See here: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Concepts/ObjectOwnership.html#/ /apple_ref/doc/uid/2043-1000698 That explicitly discusses retain cycles and the use of weak references to break them. Thanks for the link. Regards Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 12:21 PM, Andreas Mayer wrote: I'm wondering if there is a general rule or mechanism that suggests what to do in such a case. About retain cycles: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Concepts/ObjectOwnership.html "The solution to the problem of retain cycles is that the “parent” object should retain its “children,” but that the children should not retain their parents." For instance, how are delegates implemented in AppKit, are they retained? http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/chapter_6_section_4.html "Delegating objects do not (and should not) retain their delegates." Thanks for those links. But there are still cases where it is unknown which of the objects is going to be released first Care to name one? For example NSCollectionView, NSCollectionViewItem and its view. One may or may not suspect the NSCollectionViewItem owns the corresponding view. It may as well not own it and instead the NSCollectionView owns both. Of course once you run into a retain cycle problem with this and no NSCollectionViewItem ever gets released because of it (like I did) you quickly learn why and who owns the view. The point is, unless this is documented explicitly the ownership relations are not clear all the time. I generally do not find it difficult to decide which object needs to own which. In case you can't decide, maybe neither should and you are better off adding a third object that handles both. Agreed, if it's in your own power and you know what your structure looks like it's simple. Regards Markus -- __ Markus Spoettl smime.p7s Description: S/MIME cryptographic signature ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
On Jul 21, 2008, at 1:50 PM, Markus Spoettl wrote: By changing the reference from B to A to a weak reference which doesn't retain and release A, the problem goes away. However, generally speaking this is dangerous road to go (and against memory management guidelines) Actually, it is not against the guidelines, it is in keeping with them. See here: http://developer.apple.com/documentation/Cocoa/Conceptual/ MemoryMgmt/Concepts/ObjectOwnership.html#//apple_ref/doc/uid/ 2043-1000698 That explicitly discusses retain cycles and the use of weak references to break them. For instance, how are delegates implemented in AppKit, are they retained? There are not retained by virtue of being assigned as a delegate. They are retained by whatever code made the decision to assign them as the delegate. If that code later decides to release the object, it must also unset it as a delegate first. Cheers, Ken ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]
Re: Avoiding mutual retain cycles
Am 21.07.2008 um 20:50 Uhr schrieb Markus Spoettl: I'm wondering if there is a general rule or mechanism that suggests what to do in such a case. About retain cycles: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Concepts/ObjectOwnership.html "The solution to the problem of retain cycles is that the “parent” object should retain its “children,” but that the children should not retain their parents." For instance, how are delegates implemented in AppKit, are they retained? http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/chapter_6_section_4.html "Delegating objects do not (and should not) retain their delegates." But there are still cases where it is unknown which of the objects is going to be released first Care to name one? I generally do not find it difficult to decide which object needs to own which. In case you can't decide, maybe neither should and you are better off adding a third object that handles both. Andreas___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [EMAIL PROTECTED]