Find Where Object Is Retained with Arc

Find where object is retained with ARC

To track growth of an application, Heapshot Analysis has proven very effective. It will capture both true leaks and accretion of memory where the allocations are not accounted for by leaks.

You can see all of the retain/release events, and their backtrace, using the Allocations instrument. Hit the little (i) button on the Allocations instrument and turn on "Record reference counts". Turning on "Only track active allocations" reduces the amount of data collected by Instruments, making it snappier (and dead allocations aren't really useful in this context, but can be in others).

With that, you can dive into any allocation (by clicking on the right-arrow in the address field), see all the retain/release events and see exactly where they occurred.

Sample Image

How can I determine what objects ARC is retaining using Instruments or viewing assembly?

You should definitely focus on the assembly output. There are two views I find most useful: the Instruments view, and the Assembly assistant editor. The problem is that Swift doesn't support the Assembly assistant editor currently (I typically do this kind of thing in ObjC), so we come around to your complaint.

It looks like you're already working with the debug assembly view, which gives somewhat decent symbols and is useful because you can step through the code and hopefully see how it maps to the assembly. I also find Hopper useful, because it can give more symbols. Once you have enough "unique-ish" function calls in an area, you can usually start narrowing down how the assembly maps back to the source.

The other tool I use is to step into the retain bridge and see what object is being passed. To do this, instruction-step (^F7) into the call to swift_bridgeObjectRetain. At that point, you can call:

p (id)$rdi

And it should print out at least some type information about the what's being passed ($rdi is correct on x86_64 which is what you seem to be working with). I don't always have great luck extracting more information. It depends on exactly is in there. For example, sometimes it's a ContiguousArrayStorage<Swift.CVarArgType>, and I happen to have learned that usually means it's an NSArray. I'm sure better experts in LLDB could dig deeper, but this usually gets me at least in the right ballpark.

(BTW, I don't know why I can't call p (id)$rdi before jumping inside bridgeObjectRetain, but it gives strange type errors for me. I have to go into the function call.)

Wish I had more. The Swift tool chain just hasn't caught up to where the ObjC tool chain is for tracing this kind of stuff IMO.

Objective-C Is There a Way to Look at an Object Retain Count Table on the Run?]

You can access the retain count using -retainCount or CFGetRetainCount but it will almost never give you any meaningful or useful information. Objects can be added to autorelease pools, retained by the various internals of the objective-c runtime or Apple frameworks, ARC, etc. You shouldn't really care how many people have retained an object, only whether you need a strong reference to it at any point in time.

Relevant link: whentouseretaincount.com

ARC circular retain detection

The best way is usually to use the Leaks instrument in the Instruments app.

The What's New In Instruments video from WWDC 2011 discusses using Instruments to find retain cycles under ARC, starting about 38 minutes in.

Retain Cycle in ARC

A retain cycle is a situation when object A retains object B, and object B retains object A at the same time*. Here is an example:

@class Child;
@interface Parent : NSObject {
Child *child; // Instance variables are implicitly __strong
}
@end
@interface Child : NSObject {
Parent *parent;
}
@end

You can fix a retain cycle in ARC by using __weak variables or weak properties for your "back links", i.e. links to direct or indirect parents in an object hierarchy:

@class Child;
@interface Parent : NSObject {
Child *child;
}
@end
@interface Child : NSObject {
__weak Parent *parent;
}
@end



* This is the most primitive form of a retain cycle; there may be a long chain of objects that retain each other in a circle.

Increased retain count when converting to ARC

The absolute retain count is meaningless. You need to find all the spots where retain is called (or called by implication, in the case of ARC).

To do that, use the Allocations instrument and turn on reference count tracking. That'll give you access to the backtrace of every single retain and you can find the extra one.

More likely than not it'll be a strong reference to self in a block held by something in self. Or it'll be a cycle of strong references; self -> other -> self kinda thing.

Does ARC retain objects alloced inside a method parameter

The article is wrong.

Your understanding is essentially correct, though the autorelease pool is not used in this case. The sub-expression:

[[NSString alloc] initWithFormat:@"Name 1"]];

returns an owned object, as do all init methods. That object is passed to addObject: and the array also takes ownership. After that ARC sees the string is no longer required by the method and relinquishes its ownership - leaving the array as the only owner.

HTH



Related Topics



Leave a reply



Submit