从 Leopard开始,苹果在XCode系列开发工具中增加了一个新的功能强大的性能调试工具,叫做Instruments。Instruments是一个 非常具有新意的调试工具,如果你使用过iLife中非常简单易用的音乐创作工具GarageBand,你会发现这两者的界面非常类似。能够把开发工具的 UI做成像音乐创作软件的形式,可能也只有苹果能够想到了。

Instrument 里提供了极多的功能,可以针对程序的各个方面进行优化调试。对于初学者来说,虽然这个软件的界面极为友好,完全不同于以往的任何开发调试工具,但是如果能 够有一篇简单的教学,手把手地通过一个例子用Instruments进行调试,那么就更容易上手了。

 

本篇文章通过一个简单例子,带你学习如何使用Instruments工具解决应用程序中的内存泄露问题,特别适合初学者阅读。在阅读之前,如果你对Objective-C的内存管理还不是十分了解,推荐先阅读本站之前的两篇文章:

 

Objective-C 2.0之前需要了解的:关于Obj-C内存管理的规则

关于Objective-C 2.0 的垃圾收集

 

这样可以更好地理解内存泄露是如何发生的,以及更好地通过本文了解如何快速地解决这一问题。

 

本文是Matt Long最新的一篇文章,原文为英文,本站已经将其翻译成中文。

 

原文地址:

http://www.cimgf.com/2008/04/02/cocoa-tutorial-fixing-memory-leaks-with-instruments

 

当我写完程序代码,希望尽快放出新版本的时候,烦人的修改内存泄露、优化代码和去除bug是我最近主要在做的事情。程序开发中的创建新功能和解决新问题的有趣部分已经过去了。现在要做的事情需要花费很多时间,而且非常辛苦。

 

我 知道针对这些方面的优化花费些时间是很值得的事情,因为程序会更稳定更出彩,但是进行这些优化和解决这些问题真的是一个非常辛苦的工作。不过很幸运地,随 着Leopard的发布,苹果提供了一些新的工具。对于这样的调试工作,我们可以使用一个叫做Instruments的工具使其变得简单一点。

 

和往常一样,我写了一个demo程序可以让你看到这些调试是如何工作的。你可以在这里下载。这个教学中,我仅仅告诉你如何使用Instruments检测内存泄露。这个工具的使用并不难,但是可能有一些细节你可能还不熟悉。看完这个教学,你就会习惯使用这个强大的工具了。

 

在XCode中运行Instruments

 

你 可以直接运行Instruments,然后打开你的项目,但是更简单的方法是直接在XCode中调用Instruments。具体操作方法是在XCode 里打开demo项目,或者是你自己的项目(需要先编译一下),然后在菜单中选择 Run -> Start With Performance Tool -> Leaks。

 

在研究这个项目时,我和Marcus(cimgf的另一位作者)列出了一些你在使用Instruments时需要记住的事情。

 

- 断点不会中断

 

Instruments 在你的debug项目中使用debug信息,但是并不会在你设置的断点中自动中断。这是因为当你通过菜单将程序在Instruments中读取 时,Instruments使用当前的执行文件路径作为启动路径,从XCode外部调用。如果你希望使用断点,你可以关掉Instruments再执行程 序。

- NSLog的内容不会在Debugger窗口中显示

如果你希望看到NSLog中的内容,你需要手工开启终端程序。

 

- 内存泄露的产生

 

本来我们期待如果我们为一个新建的NSString *对象分配内存,我们就可以直接看到内存的泄露。这本来是我们的目的,可是事情并非所想那样。下面这段代码在我们的测试中根本就不会产生任何内存泄露。

 

NSString *string = [[NSString alloc] initWithString:@"Leaker"];

 

原因是这样的,NSString本身是不可以修改的,我们使用了@操作符分配了字符串的内存之后,编译器帮助我们提高了程序的效率。编译器自动把具有相同内容的字符串分配了相同的地址。

 

(Cocoachina解释:也就是说 string 和 @"Leaker"的地址通过编译器编译后,是同一个,而如果你看过之前的文章,你就会知道”Leaker”这个字符串在程序运行期间是永远不会被释放的,这样一来,string也就不用释放,也就不存在内存泄露问题了。但是这仅仅是编译器的优化,并不能保证任何情况下都是这样。)

 

在这段例子代码中,NSString永远不会泄露,那这段例子也就没什么用了。并不是说这种写法的NSString永远不会泄露,所以你应该习惯地在不需要NSString时,调用-release方法去释放它们。不过在我们的测试里,NSString的内存泄露从来没有被检测到。而当我们把NSString换成NSMutableString时,正如所想,内存泄露开始显现。

 

检测内存泄露

 

当 Instruments读入你的程序之后,你会看到ObjectAlloc这个轨道开始随时间变化填充内容了。要在项目中检测泄露,点击Leaks轨道, 然后观察Leak Status分类。这个分类随时间变化检测内存泄露。同样,你还可以直接在Check Manually分类下点击“Check for Leaks Now”按钮进行手动检测内存泄露。

 

当内存泄露检测开始时,你会看到列表中出现了泄露的对象,如果你希望看到内存泄露的细节,点击列表中的对象,然后点击屏幕下方的 Extended Detail 按钮(如图所示)。

点击之后,你会看到Instruments右侧出现了Stack Trace列表。检查一下列表中类似这种代码。你自己的Instruments列表中的颜色可能和例子中不一样。

 

(你需要找的是类似这种列表项,上方是方法,下面是提示:程序名称,行数。)

 

当你找到内存中泄露的地方,双击之后,Instruments就会自动帮你切换到XCode出现泄露的具体程序行数。

 

要修改内存泄露,你需要确定你释放了对象。关于如何释放,可以参阅本站的文章:

 

Objective-C 2.0之前需要了解的:关于Obj-C内存管理的规则

 

结论

 

发 现和修改问题并不是开发中最有趣的部分,不过当你真的做了这些,结果是非常有益处的。Instruments对你的程序提供了线形的跟踪,帮助你跟踪你所 关心的程序的任何一部分。如果你希望更多了解Instruments,点击Instruments菜单上方工具条的Library按钮,看一下它都提供了 哪些方面的调试功能,真的非常棒。