Archive for the 'Objective-C' Category

retainCount is useless.

Sunday, December 18th, 2011

The retainCount method just isn’t very useful as has been indicated in the answers to about a zillion StackOverflow questions.

The documentation has this to say:

Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.

Makes it pretty clear that you shouldn’t be calling retainCount, but it really doesn’t illuminate exactly how useless the method is outside of a very narrow context.

So, let us count the ways:

  1. The absolute retain count of an object may change at any time once an object has been passed through any system API.
  2. Any subclass of any system provided class counts as “through system API”; the retain count may be impacted by implementation details.
  3. The retain count never reflects whether an object is autoreleased.
  4. Autorelease is a per-thread concept whereas retain counts are global; race condition derived hilarity can easily ensue.
  5. The retainCount method can never return 0.
  6. Some classes are implemented as singletons some of the time.
  7. Some classes may internally manipulate their retain count directly (I.e. no swizzle for you!).
  8. While retain/release are effectively thread safe, there is always a race between calling retainCount and having the actual retain count change in some other execution context.

Bottom line: the only time the absolute retainCount can be conclusively used for analytic purposes is if you have the backtrace of every retain and release that contributed to the current retain count’s value (there is another use case, documented at the end). If you have that, then you don’t need the retain count and, fortunately, Instruments is already generally quite adept at producing a per-object inventory of retains and releases for you (see Analyzing Data with the Allocations Instrument“.

In general, you should consider the retain count as a delta. Your code causes the retain count to increase and decrease. You don’t +alloc an object with a retain count of 1. Instead, you +alloc an object with a retain count of +1. If you want that object to go away, you need to do something — release, always and eventually — that causes the retain count to be decremented by 1.

It really is that simple.

Almost.

Concurrency — whether through threading or GCD — throws a bit of a wrench in the works (as it always does). Namely, the retain count should really be considered as a per concurrency context delta. If thread or queue A wants to do something with object X, it should hold a +1 retainCount on X for the duration of said operation. One subtle detail that will bear repeating later; an autorelease‘d object does not contribute to thread safety. That is, if thread or queue A wants to pass X to thread or queue B, there must be an explicit retain in A that is balanced by a release (or synchronization event back to A) in B.

Now, some of the enumerated claims may either seem specious at best or, certainly, not obvious as to exactly how it undermines the validity of the retain count. Read the rest of this entry »

iOS 4.3: imp_implementationWithBlock()

Thursday, March 17th, 2011

In iOS 4.3, there are 3 rather low level functions in the runtime that provide a new kind of bridge between Objective-C and Blocks with a specific goal of facilitating the dynamic generation of method implementations.

Specifically:

IMP imp_implementationWithBlock(void *block);
void *imp_getBlock(IMP anImp);
BOOL imp_removeBlock(IMP anImp);

In particular, imp_implementationWithBlock() takes a block as a parameter, copies it to the heap, and returns a trampoline that allows the block to be used as the implementation — the IMP — of a method in any Objective-C class (as long as the block’s arguments and the method’s arguments are compatible).

Quite literally, this allows:

int j = 12;
IMP skewIMP = imp_implementationWithBlock(^(id _s, int k) { return k*j; });

Where skewIMP would then contain a function pointer that could be used as the IMP for a method declared like:

- (int)skew:(int)k;

Details on the flip side…. Read the rest of this entry »

When is a Leak not a Leak? Using Heapshot Analysis to Find Undesirable Memory Growth

Sunday, October 17th, 2010

The other day, I was in need of a Cocoa application that launches quickly that has a standard document model. At random, I chose the rather awesome Hex Fiend. As I often do, I also had top -u -o pid running in a Terminal window.

And I noticed something odd. As expected, the RPRVT of Hex Fiend was growing on each cmd-n. However, the RPRVT was not decreasing the same amount every time I hit cmd-w.

That ain’t right. Or it might be. Beyond evidence that a memory use problem may exist, top is a horrible tool for determining if a problem is real or what the actual problem might be.

In this case, the issue looks like a simple memory leak. Hex Fiend is allocating and retaining some set of objects, but not releasing them. The easiest first step is to use the leaks command line tool:

% leaks "Hex Fiend"
leaks Report Version:  2.0
Process:         Hex Fiend [3435]
Path:            /Volumes/Data/Applications/Hex Fiend.app/Contents/MacOS/Hex Fiend
Load Address:    0x100000000
Identifier:      com.ridiculousfish.HexFiend
Version:         2.0.0 (200)
Code Type:       X86-64 (Native)
Parent Process:  launchd [122]
Date/Time:       2010-10-16 20:47:09.935 -0700
OS Version:      Mac OS X 10.6.4
Report Version:  7
Process 3435: 22980 nodes malloced for 2600 KB
Process 3435: 0 leaks for 0 total leaked bytes.

OK; whatever the problem is, it isn’t “leaked” memory in the traditional definition of “leaked memory”.

That is, whatever memory is being allocated and never released is still being referenced somewhere. Maybe a circular retain. Maybe something that has a weak reference from the rest of the App’s object graph such that leaks can’t detect.

In other words, this isn’t just a simple memory leak and it will require more advanced tools to fix.

Read the rest of this entry »

Obvious Programming Tip: Check Those Bit Patterns

Sunday, July 25th, 2010
RedonkulouslyLargeNumber.png

Sometimes, when tracking down a bug, you’ll get a bit of console spew, an exception log, or a crash log that contains a ridiculously large number. Sometimes, that is the result of a memory smasher.

Sometimes, though, it is because of a type conversion problem.

For example, if you see a log message indicating that the value 4294967295 is causing a problem, it is probably because something archived -1 on a 32 bit system and then unarchived it on 64 bit improperly.

This has come up often enough that I like to leave the Calculator app open in Programmer Mode. Then, I can copy/paste the value into Calculator and see both the bit pattern or the hex value (which will often show patterns that base-10 does not).

An aside, I have generally tried to break myself of the habit of relying upon knowledge of magic values (like 4294967295). Sure, I’ll use ’em as clues, but I focus much more on refining my tools to make recognition of said values unnecessary as there are a slew of different values that look non-obvious in decimal form that become darned obvious in binary or hex.

Dead obvious, I know.

objc_msgSend() Tour Part 4: Method Lookup & Some Odds and Ends

Thursday, February 4th, 2010

Table of Contents

  1. objc_msgSend() Tour Part 1: The Road Map
  2. objc_msgSend() Tour Part 2: Setting the Stage
  3. objc_msgSend() Tour Part 3: The Fast Path
  4. objc_msgSend() Tour Part 4: Method Lookup & Some Odds and Ends

In the first three parts, I gave an overview, explained a bit of the ABI used by Objective-C, and took a near instruction by instruction tour of what happens on the fast path of Objective-C method dispatch. By fast path, I mean what happens 99.9% of the time; a very fast, no overhead, no function call, no locking, set of instructions that grabs the method implementation from the cache and does a tail-call jump to that implementation.

The slow path is used rarely. As little as once per unique selector invoked per class with a goal of filling the cache such that the slow path is never used again for that selector/class combination. A handful of operations will cause a class’s cache to be flushed; method swizzling, category loading, and the like.

Note that during +initialize, methods won’t always be cached. Yet another reason to not do any real work during +initialize! Read the rest of this entry »

Using malloc to Debug Memory Misuse in Cocoa

Sunday, January 10th, 2010

Every few months, there is a discussion on cocoa-dev or a question on stackoverflow.com that basically boils down to “I have a leak or over-release and I can’t use Instruments to debug it. Help?”.

Quite often, the questioner can actually use Instruments just fine, but simply lacks the know-how or hasn’t tried in a while and doesn’t realize that Instruments has improved significantly with each release of the developer tools. No, really, Instruments is a fantastic tool and I use it whenever I can; what you see below is for the exceptional case, not the norm.

There are cases where using Instruments is either inconvenient or impractical. Namely, trying to track down an intermittent crasher or trying to gain insight into memory leaks over a long running session will create a prohibitively large dataset for Instruments to process (Instruments allows for much more detailed analysis of the object graph and this analysis loads a lot more data than the tools I’ll demonstrate below).

Thus, it is helpful to be familiar with the rather powerful set of tools available from the command line and within the debugger.

Almost always, you are going to want to enable a bit of additional data via the malloc infrastructure. Have a look at the malloc(3) man page. There is an entire section devoted to ENVIRONMENT variables and there are a handful of extremely useful variables!

First and foremost, you are almost always going to want to use MallocStackLoggingNoCompact. When enabled, malloc stack logging writes the stack trace of every allocation and free event to an efficiently compact binary file in /tmp/ (it used to be in memory and, thus, used to be a great way to exhaust heap. No longer!!). Unfortunately, it doesn’t record the retain and release events, but simply knowing where the object was allocated is generally quite useful (it is generally relatively easy to track down who retained an object once you know which object it is). Under GC, you can set the AUTO_REFERENCE_COUNT_LOGGING and CFRetain/CFRelease events will be logged to the malloc history.

You can then use the malloc_history command line tool to query for all events related to a particular address in memory.

While malloc_history requires that the process still exists, it doesn’t have to be running! If you run your app under gdb, you can still use malloc_history to query the application even when it is stopped in the debugger!

Speaking of gdb, you can use the info malloc command in gdb to query the same information. Under GC, the info gc-roots and info gc-referers commands can be used to interrogate the collector for information about the connectivity of the object graph in your running application.

If you enable zombies via setting the NSZombieEnabled environment variable to YES, the address spewed in the error message when messaging a zombie can be passed directly to malloc_history.

The leaks command line tool scans memory and detects leaks in the form of allocations of memory for which the address to that memory is not stored anywhere else within the application. The leaks tool has been vastly improved in the Snow Leopard release of the Xcode tools; it is much much faster and spits out false positives almost never. It is still possible to have a leak that leaks cannot detect, of course. And, remember, even if you can still reach memory, it is still a total waste if you never use that memory’s contents again!

So, that is a brief summary of the state of command line memory debugging on Mac OS X as of Snow Leopard. Of course, that’s just a bunch of words. How about an example?

Read the rest of this entry »

objc_msgSend() Tour Part 3: The Fast Path

Friday, December 18th, 2009

Table of Contents

  1. objc_msgSend() Tour Part 1: The Road Map
  2. objc_msgSend() Tour Part 2: Setting the Stage
  3. objc_msgSend() Tour Part 3: The Fast Path
  4. objc_msgSend() Tour Part 4: Method Lookup & Some Odds and Ends

In any case, with the foundation set — with the id of the object to be targeted in %rdi and the selector of the method to be invoked in %rsi — we can jump into objc_msgSend() and understand exactly what happens instruction by instruction. Or more specifically, the compiler issues a call into objc_msgSend() (which sets up a stackframe for objc_msgSend() which, through tail call optimization, turns into the stackframe for the called method) and the method implementation that objc_msgSend() jumps to will issue a ret instruction to unwind the stack back to the original caller’s frame.

It is pretty easy to correlate the disassembly with the comments and code in the original source file. However, if you ever need to step through the messenger (si steps by instruction in gdb), this will be easier to follow as this is closer to the reality during a debug session.

For almost all method dispatches, dispatch takes what is called the “fast path”. That is, objc_msgSend() finds the implementation in the method cache and passes control to the implementation. Since this is the most common path, it is a good opportunity to break the tour of objc_msgSend() into two parts; the fast path and the slow path (with administrivia).

Read the rest of this entry »

objc_msgSend() Tour Part 2: Setting the Stage

Friday, December 18th, 2009

Table of Contents

  1. objc_msgSend() Tour Part 1: The Road Map
  2. objc_msgSend() Tour Part 2: Setting the Stage
  3. objc_msgSend() Tour Part 3: The Fast Path
  4. objc_msgSend() Tour Part 4: Method Lookup & Some Odds and Ends

Objective-C is, ultimately, a simple set of extensions to C that provide an object oriented coding and runtime model. Objective-C fully embraces C and leverages the C calling ABI throughout. Every method call is really just a C function call with objc_msgSend() acting as the preamble that figures out exactly which C function — which method — to call!

Thus, it is helpful to understand how objc_msgSend() is called and how that relates to C. That is, how does the compiler translate [someObject doSomething: 0x2a] into a call.

What follows is a bit of code that makes a [totally bogus] simple method call followed by the assembly generated.

Code:
@interface NSObject(foo)
- (id) doSomething: (NSUInteger) index;
@end
...
    NSObject *b;
    NSArray *a;
    b = [a doSomething: 0x2a]; // line 11
Assembly:
    .loc 1 11 0
    movq	-16(%rbp), %rdi
    movq	L_OBJC_SELECTOR_REFERENCES_0(%rip), %rsi
    movl	$42, %edx
    call	_objc_msgSend
    movq	%rax, -8(%rbp)

Read the rest of this entry »

objc_msgSend() Tour Part 1: The Road Map

Friday, December 18th, 2009

What follows (across this and 3 more posts, maybe more) is a rather detailed tour of objc_msgSend() as implemented in Mac OS X 10.6.2. Rather detailed in that every instruction will be explained. Even though it is relatively few instructions, there is a considerable amount of background information that is helpful to understanding the objc_msgSend() instruction stream.

The motivation behind these posts is entirely selfish. I find the best way for me to learn something is to know it well enough to be able to explain any detail to a room full of folks in full-blown student mode.

Table of Contents

  1. objc_msgSend() Tour Part 1: The Road Map
  2. objc_msgSend() Tour Part 2: Setting the Stage
  3. objc_msgSend() Tour Part 3: The Fast Path
  4. objc_msgSend() Tour Part 4: Method Lookup & Some Odds and Ends

Read the rest of this entry »

Calling Python from Objective-C

Saturday, November 21st, 2009

Every six months or so, I run across a question along the lines of how do I invoke some Python code from Objective-C?

Kinda like here for which I posted the same conceptually concrete but technically vague pattern that I have posted for the last decade+.

Which led to this question.

OK — enough is enough. Here is a working example. Read the rest of this entry »